Skip to content

Commit

Permalink
Revert "Merge pull request mockk#1025 from aSemy/fix/dedupe_proxymaker"
Browse files Browse the repository at this point in the history
This reverts commit cac70d9, reversing
changes made to 7d322e3.

# Conflicts:
#	modules/mockk-agent-api/src/jvmMain/kotlin/io/mockk/proxy/common/ProxyMaker.kt
  • Loading branch information
LeonRa authored and SimonMarquis committed Sep 12, 2023
1 parent d64dbda commit 641ec02
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,11 @@ internal class AndroidSubclassInstrumentation(

return abstractMethods.map { it.originalMethod }.toTypedArray()
}
}

override fun setProxyHandler(proxy: Any, handler: MockKInvocationHandler) {
if (ProxyBuilder.isProxyClass(proxy::class.java)) {
ProxyBuilder.setInvocationHandler(proxy, ProxyInvocationHandler(handler))
}
}

}
1 change: 1 addition & 0 deletions modules/mockk-agent-api/api/mockk-agent-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public abstract class io/mockk/proxy/common/transformation/RetransformInlineInst
}

public abstract interface class io/mockk/proxy/common/transformation/SubclassInstrumentation {
public abstract fun setProxyHandler (Ljava/lang/Object;Lio/mockk/proxy/MockKInvocationHandler;)V
public abstract fun subclass (Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/Class;
}

Expand Down
1 change: 0 additions & 1 deletion modules/mockk-agent-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("reflect"))
}
}
val commonTest by getting {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package io.mockk.proxy.common.transformation

import io.mockk.proxy.MockKInvocationHandler

interface SubclassInstrumentation {
fun <T> subclass(
clazz: Class<T>,
interfaces: Array<Class<*>>
): Class<T>

fun setProxyHandler(proxy: Any, handler: MockKInvocationHandler)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ data class TransformationRequest(
type,
!untransform
)
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.mockk.proxy.common

import io.mockk.proxy.*
import io.mockk.proxy.common.transformation.InlineInstrumentation
import io.mockk.proxy.common.transformation.TransformationRequest
import io.mockk.proxy.common.transformation.SubclassInstrumentation
import io.mockk.proxy.common.transformation.TransformationRequest
import io.mockk.proxy.common.transformation.TransformationType
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.lang.reflect.Proxy

class ProxyMaker(
private val log: MockKAgentLogger,
Expand All @@ -30,7 +32,6 @@ class ProxyMaker(
private val instantiator: MockKInstantiatior,
private val handlers: MutableMap<Any, MockKInvocationHandler>
) : MockKProxyMaker {

override fun <T : Any> proxy(
clazz: Class<T>,
interfaces: Array<Class<*>>,
Expand All @@ -41,24 +42,31 @@ class ProxyMaker(

throwIfNotPossibleToProxy(clazz, interfaces)

// Sometimes (e.g. in case of sealed classes) we will create the proxy for a subclass of `clazz` and not `clazz`
// itself. We need to determine this early, so that the subclass will be inlined as well.
val actualClass = findActualClassToBeProxied(clazz)
if (clazz.isInterface) {
val proxyInstance = Proxy.newProxyInstance(
clazz.classLoader,
interfaces + clazz,
ProxyInvocationHandler(handler)
)

val cancellation = inline(actualClass)
return CancelableResult(clazz.cast(proxyInstance))
}

val cancellation = inline(clazz)

val result = CancelableResult<T>(cancelBlock = cancellation)

val proxyClass = try {
subclass(actualClass, interfaces)
subclass(clazz, interfaces)
} catch (ex: Exception) {
result.cancel()
throw MockKAgentException("Failed to subclass $actualClass", ex)
throw MockKAgentException("Failed to subclass $clazz", ex)
}

try {
val proxy = instantiate(actualClass, proxyClass, useDefaultConstructor, instance)
val proxy = instantiate(clazz, proxyClass, useDefaultConstructor, instance)

subclasser.setProxyHandler(proxy, handler)
handlers[proxy] = handler
return result
.withValue(proxy)
Expand All @@ -67,6 +75,7 @@ class ProxyMaker(
}
} catch (e: Exception) {
result.cancel()

throw MockKAgentException("Instantiation exception", e)
}
}
Expand Down Expand Up @@ -99,7 +108,11 @@ class ProxyMaker(
val superclasses = getAllSuperclasses(clazz)

return if (inliner != null) {
val transformRequest = TransformationRequest(superclasses, TransformationType.SIMPLE)
val transformRequest =
TransformationRequest(
superclasses,
TransformationType.SIMPLE
)

inliner.execute(transformRequest)
} else {
Expand All @@ -111,31 +124,13 @@ class ProxyMaker(
}
}

private fun <T : Any> findActualClassToBeProxied(
clazz: Class<T>,
): Class<T> {
val kClass = clazz.kotlin
if (!kClass.isSealed) {
return clazz
}

val subclass = kClass.sealedSubclasses.firstOrNull()?.java
?: error("Unable to create proxy for sealed class $clazz, no subclasses available")
log.trace("Class $clazz is sealed, will use its subclass $subclass to build proxy")
@Suppress("UNCHECKED_CAST")
return findActualClassToBeProxied(subclass) as Class<T>
}

private fun <T : Any> subclass(
clazz: Class<T>,
interfaces: Array<Class<*>>
): Class<T> {
return if (Modifier.isFinal(clazz.modifiers)) {
log.trace("Taking instance of $clazz itself because it is final.")
clazz
} else if (interfaces.isEmpty() && !Modifier.isAbstract(clazz.modifiers) && inliner != null) {
log.trace("Taking instance of $clazz itself because it is not abstract and no additional interfaces specified.")
clazz
} else {
log.trace(
"Building subclass proxy for $clazz with " +
Expand Down Expand Up @@ -174,7 +169,7 @@ class ProxyMaker(
val defaultConstructor = cls.getDeclaredConstructor()
try {
defaultConstructor.isAccessible = true
} catch (ignored: Exception) {
} catch (ex: Exception) {
// skip
}

Expand All @@ -199,7 +194,6 @@ class ProxyMaker(


companion object {

private val notMockableClasses = setOf(
Class::class.java,
Boolean::class.java,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package io.mockk.proxy.jvm

import io.mockk.proxy.*
import io.mockk.proxy.common.ProxyMaker
import io.mockk.proxy.common.transformation.ClassTransformationSpecMap
import io.mockk.proxy.jvm.advice.jvm.MockHandlerMap
import io.mockk.proxy.jvm.dispatcher.BootJarLoader
import io.mockk.proxy.jvm.transformation.InliningClassTransformer
import io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation
import io.mockk.proxy.jvm.transformation.JvmSubclassInstrumentation
import io.mockk.proxy.jvm.transformation.SubclassInstrumentation
import net.bytebuddy.ByteBuddy
import net.bytebuddy.NamingStrategy
import net.bytebuddy.agent.ByteBuddyAgent
Expand Down Expand Up @@ -92,8 +91,8 @@ class JvmMockKAgentFactory : MockKAgentFactory {
)
}

val subclasser = JvmSubclassInstrumentation(
logFactory.logger(JvmSubclassInstrumentation::class.java),
val subclasser = SubclassInstrumentation(
logFactory.logger(SubclassInstrumentation::class.java),
handlers,
byteBuddy
)
Expand Down

0 comments on commit 641ec02

Please sign in to comment.