From ffb7484456f60e6ae0b1f8cdb7804698db956eba Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Tue, 31 May 2022 17:23:42 +0100 Subject: [PATCH 1/6] dynamic proxy cleanups --- .../ProxyInstantiationException.scala | 8 ++++ .../provisioning/proxies/ProxyProvider.scala | 2 +- ...vider.scala => DynamicProxyProvider.scala} | 2 +- .../distage/bootstrap/CglibBootstrap.scala | 7 --- .../bootstrap/DynamicProxyBootstrap.scala | 8 ++++ .../distage/bootstrap/CglibBootstrap.scala | 7 --- .../bootstrap/DynamicProxyBootstrap.scala | 20 +++++++++ .../injector/CglibProxiesTestJvm.scala | 44 +++++++++---------- .../distage/bootstrap/BootstrapLocator.scala | 6 +-- .../scala/izumi/distage/gc/GcBasicTests.scala | 2 +- .../scala/izumi/distage/gc/MkGcInjector.scala | 2 +- .../injector/CircularDependenciesTest.scala | 8 ++-- .../distage/injector/InnerClassesTest.scala | 2 +- .../izumi/distage/injector/MkInjector.scala | 2 +- .../distage/impl/OptionalDependencyTest.scala | 6 ++- 15 files changed, 75 insertions(+), 51 deletions(-) create mode 100644 distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/interpretation/ProxyInstantiationException.scala rename distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/{CglibProxyProvider.scala => DynamicProxyProvider.scala} (97%) delete mode 100644 distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala create mode 100644 distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala delete mode 100644 distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala create mode 100644 distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/interpretation/ProxyInstantiationException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/interpretation/ProxyInstantiationException.scala new file mode 100644 index 0000000000..7abdccdf5b --- /dev/null +++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/interpretation/ProxyInstantiationException.scala @@ -0,0 +1,8 @@ +package izumi.distage.model.exceptions.interpretation + +import izumi.distage.model.exceptions.DIException +import izumi.distage.model.plan.ExecutableOp +import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams + +class ProxyInstantiationException(message: String, val target: Class[?], val params: ProxyParams, val op: ExecutableOp, cause: Throwable) + extends DIException(message, cause) diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala index a8bb5a44c7..99841284d5 100644 --- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala +++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala @@ -10,7 +10,7 @@ trait ProxyProvider { } object ProxyProvider { - class ProxyProviderFailingImpl extends ProxyProvider { + object ProxyProviderFailingImpl extends ProxyProvider { override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = { throw new ProxyProviderFailingImplCalledException(s"ProxyProviderFailingImpl can't create cycle-breaking proxies, failed op: ${proxyContext.op}", this) } diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala similarity index 97% rename from distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala rename to distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala index 304eec8ada..4b327b8a54 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala +++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala @@ -8,7 +8,7 @@ import izumi.distage.provisioning.strategies.cglib.exceptions.CgLibInstantiation import izumi.fundamentals.platform.exceptions.IzThrowable._ import net.sf.cglib.proxy.{Callback, Enhancer} -class CglibProxyProvider extends ProxyProvider { +object DynamicProxyProvider extends ProxyProvider { override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = { val nullDispatcher = new CglibNullMethodInterceptor(deferredKey) diff --git a/distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala b/distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala deleted file mode 100644 index cc187d2780..0000000000 --- a/distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala +++ /dev/null @@ -1,7 +0,0 @@ -package izumi.distage.bootstrap - -import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyProviderFailingImpl - -object CglibBootstrap { - type CglibProxyProvider = ProxyProviderFailingImpl -} diff --git a/distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala b/distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala new file mode 100644 index 0000000000..c7915f3d4a --- /dev/null +++ b/distage/distage-core/.js/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala @@ -0,0 +1,8 @@ +package izumi.distage.bootstrap + +import izumi.distage.model.provisioning.proxies.ProxyProvider +import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyProviderFailingImpl + +object DynamicProxyBootstrap { + val DynamicProxyProvider: ProxyProvider = ProxyProviderFailingImpl +} diff --git a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala deleted file mode 100644 index ed346b27d2..0000000000 --- a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/CglibBootstrap.scala +++ /dev/null @@ -1,7 +0,0 @@ -package izumi.distage.bootstrap - -import izumi.distage.provisioning.strategies.cglib - -object CglibBootstrap { - type CglibProxyProvider = cglib.CglibProxyProvider -} diff --git a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala new file mode 100644 index 0000000000..18110a3f2b --- /dev/null +++ b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala @@ -0,0 +1,20 @@ +package izumi.distage.bootstrap + +import izumi.distage.model.provisioning.proxies.ProxyProvider +import izumi.fundamentals.reflection.TypeUtil + +import scala.util.Try + +object DynamicProxyBootstrap { + + val dynProxyProviderName = "izumi.distage.provisioning.strategies.cglib.DynamicProxyProvider$" + val DynamicProxyProvider: ProxyProvider = + Try(TypeUtil.instantiateObject[ProxyProvider](Class.forName(dynProxyProviderName))).toOption match { + case Some(value) => + value + case None => + import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyProviderFailingImpl + ProxyProviderFailingImpl + } + +} diff --git a/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala b/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala index 742aee9d4c..1e6dedfab2 100644 --- a/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala +++ b/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala @@ -5,11 +5,9 @@ import izumi.distage.fixtures.CircularCases.* import izumi.distage.fixtures.InnerClassCases.{InnerClassStablePathsCase, InnerClassUnstablePathsCase} import izumi.distage.fixtures.ResourceCases.{CircularResourceCase, Ref, Suspend2} import izumi.distage.injector.ResourceEffectBindingsTest.Fn -import izumi.distage.model.exceptions.interpretation.ProvisioningException +import izumi.distage.model.exceptions.interpretation.{ProvisioningException, ProxyInstantiationException} import izumi.distage.model.plan.Roots -import izumi.distage.provisioning.strategies.cglib.exceptions.CgLibInstantiationOpException import izumi.fundamentals.platform.functional.Identity -import net.sf.cglib.core.CodeGenerationException import org.scalatest.wordspec.AnyWordSpec import scala.collection.immutable.Queue @@ -19,7 +17,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { "CircularDependenciesTest" should { "support circular dependencies" in { - import CircularCase1._ + import CircularCase1.* val definition = PlannerInput.everything(new ModuleDef { make[Circular2] @@ -36,7 +34,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support circular dependencies with final class implementations" in { - import CircularCase1._ + import CircularCase1.* val definition = PlannerInput.everything(new ModuleDef { make[Circular2].from[Circular2Impl] @@ -53,7 +51,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support circular dependencies in providers" in { - import CircularCase1._ + import CircularCase1.* val definition = PlannerInput.everything(new ModuleDef { make[Circular2].from { @@ -78,7 +76,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "Supports self-referencing circulars" in { - import CircularCase3._ + import CircularCase3.* val definition = PlannerInput.everything(new ModuleDef { make[SelfReference] @@ -94,7 +92,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "Support self-referencing provider" in { - import CircularCase3._ + import CircularCase3.* val definition = PlannerInput.everything(new ModuleDef { make[SelfReference].from { @@ -113,7 +111,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support proxy circular dependencies involving a primitive type" in { - import CircularCase8._ + import CircularCase8.* val definition = PlannerInput.everything(new ModuleDef { make[Circular2] @@ -137,7 +135,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support circular dependencies that use another object in their constructor that isn't involved in a cycle" in { - import CircularCase9._ + import CircularCase9.* val definition = PlannerInput.everything(new ModuleDef { make[Circular2] @@ -162,7 +160,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support fully generic circular dependencies" in { - import CircularCase5._ + import CircularCase5.* val definition = PlannerInput.everything(new ModuleDef { make[GenericCircular[Dependency]] @@ -180,7 +178,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support named circular dependencies" in { - import CircularCase4._ + import CircularCase4.* val definition = PlannerInput.everything(new ModuleDef { make[IdTypeCircular] @@ -201,7 +199,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support type refinements in circular dependencies" in { - import CircularCase6._ + import CircularCase6.* val definition = PlannerInput.everything(new ModuleDef { make[Dependency { def dep: RefinedCircular }].from[RealDependency] @@ -219,7 +217,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "support simple by-name forward ref when there are non-by-name references" in { - import CircularCase10._ + import CircularCase10.* val definition = PlannerInput( new ModuleDef { @@ -242,7 +240,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "Regression test 1: isolated cycles causing spooky action at a distance" in { - import CircularCase7._ + import CircularCase7.* val definition = PlannerInput.everything(new ModuleDef { // cycle @@ -290,8 +288,8 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { "progression test: can't find proper constructor for circular dependencies inside stable objects that contain inner classes from inherited traits that depend on types defined inside trait" in { val res = intercept[ProvisioningException] { - import InnerClassStablePathsCase._ - import StableObjectInheritingTrait._ + import InnerClassStablePathsCase.* + import StableObjectInheritingTrait.* val definition = PlannerInput.everything(new ModuleDef { make[Circular1] @@ -309,7 +307,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { "progression test: cglib proxies can't resolve circular path-dependent dependencies (we don't take prefix type into account when calling constructor for generated lambdas and end up choosing the wrong constructor...)" in { // the value prefix probably has to be stored inside the Provider to fix this val exc = intercept[ProvisioningException] { - import InnerClassUnstablePathsCase._ + import InnerClassUnstablePathsCase.* val testProviderModule = new TestModule val definition = PlannerInput.everything(new ModuleDef { @@ -322,9 +320,9 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { assert(context.get[testProviderModule.TestFactory].mk(testProviderModule.TestDependency()) == testProviderModule.TestClass(testProviderModule.TestDependency())) } - assert(exc.getSuppressed.head.isInstanceOf[CgLibInstantiationOpException]) - assert(exc.getSuppressed.head.getCause.isInstanceOf[CodeGenerationException]) - assert(exc.getSuppressed.head.getCause.getCause.isInstanceOf[NoSuchMethodException]) + assert(exc.getSuppressed.head.isInstanceOf[ProxyInstantiationException]) +// assert(exc.getSuppressed.head.getCause.isInstanceOf[CodeGenerationException]) +// assert(exc.getSuppressed.head.getCause.getCause.isInstanceOf[NoSuchMethodException]) } } @@ -332,7 +330,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { "ResourceEffectBindingsTest" should { "Support self-referencing circular effects" in { - import izumi.distage.fixtures.CircularCases.CircularCase3._ + import izumi.distage.fixtures.CircularCases.CircularCase3.* val definition = PlannerInput.everything(new ModuleDef { make[Ref[Fn, Boolean]].fromEffect(Ref[Fn](false)) @@ -353,7 +351,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector { } "Support mutually-referent circular resources" in { - import CircularResourceCase._ + import CircularResourceCase.* import ResourceEffectBindingsTest.Fn val definition = PlannerInput( diff --git a/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala b/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala index 35a8a27eb6..c9556d5a34 100644 --- a/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala +++ b/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala @@ -1,6 +1,6 @@ package izumi.distage.bootstrap -import izumi.distage.bootstrap.CglibBootstrap.CglibProxyProvider +import izumi.distage.bootstrap.DynamicProxyBootstrap.DynamicProxyProvider import izumi.distage.model.* import izumi.distage.model.definition.* import izumi.distage.model.plan.ExecutableOp.InstantiationOp @@ -138,8 +138,8 @@ object BootstrapLocator { make[BindingTranslator].from[BindingTranslator.Impl] - make[ProxyProvider].tagged(Cycles.Proxy).from[CglibProxyProvider] - make[ProxyProvider].from[ProxyProviderFailingImpl] + make[ProxyProvider].tagged(Cycles.Proxy).fromValue(DynamicProxyProvider) + make[ProxyProvider].fromValue(ProxyProviderFailingImpl) make[ProxyStrategy].tagged(Cycles.Disable).from[ProxyStrategyFailingImpl] make[ProxyStrategy].from[ProxyStrategyDefaultImpl] diff --git a/distage/distage-core/src/test/scala/izumi/distage/gc/GcBasicTests.scala b/distage/distage-core/src/test/scala/izumi/distage/gc/GcBasicTests.scala index 15fae10a79..a575a999eb 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/gc/GcBasicTests.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/gc/GcBasicTests.scala @@ -34,7 +34,7 @@ class GcBasicTests extends AnyWordSpec with MkGcInjector { "handle by-name circular dependencies with sets through refs/2" in { import GcCases.InjectorCase13._ - val injector = mkNoCglibInjector() + val injector = mkNoProxiesInjector() val plan = injector.plan( PlannerInput( new ModuleDef { diff --git a/distage/distage-core/src/test/scala/izumi/distage/gc/MkGcInjector.scala b/distage/distage-core/src/test/scala/izumi/distage/gc/MkGcInjector.scala index b29bcfd082..e3ae9cc582 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/gc/MkGcInjector.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/gc/MkGcInjector.scala @@ -16,7 +16,7 @@ trait MkGcInjector { Injector(Seq(AutoSetModule().register[AutoCloseable]) ++ more: _*) } - def mkNoCglibInjector(): Injector[Identity] = { + def mkNoProxiesInjector(): Injector[Identity] = { Injector.NoProxies(AutoSetModule().register[AutoCloseable]) } } diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala index d12cc822b4..26e653fd1e 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala @@ -68,7 +68,7 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector { make[ByNameSelfReference] }) - val injector = mkNoCglibInjector() + val injector = mkNoProxiesInjector() val plan = injector.plan(definition) val context = injector.produce(plan).unsafeGet() @@ -84,7 +84,7 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector { make[TraitSelfReference] }) - val injector = mkNoCglibInjector() + val injector = mkNoProxiesInjector() val plan = injector.plan(definition) val context = injector.produce(plan).unsafeGet() @@ -103,7 +103,7 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector { make[FactorySelfReference] }) - val injector = mkNoCglibInjector() + val injector = mkNoProxiesInjector() val plan = injector.plan(definition) val context = injector.produce(plan).unsafeGet() @@ -170,7 +170,7 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector { make[Int].from(1) }) - val injector = mkNoCglibInjector() + val injector = mkNoProxiesInjector() val plan = injector.plan(definition) val context = injector.produce(plan).unsafeGet() diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/InnerClassesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/InnerClassesTest.scala index 114fedea76..dd168b7947 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/InnerClassesTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/InnerClassesTest.scala @@ -154,7 +154,7 @@ class InnerClassesTest extends AnyWordSpec with MkInjector { make[ByNameCircular2] }) - val context = mkNoCglibInjector().produce(definition).unsafeGet() + val context = mkNoProxiesInjector().produce(definition).unsafeGet() assert(context.get[ByNameCircular1] != null) assert(context.get[ByNameCircular1].circular2 eq context.get[ByNameCircular2]) diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/MkInjector.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/MkInjector.scala index eb3064c80f..d2a9dee97e 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/MkInjector.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/MkInjector.scala @@ -5,6 +5,6 @@ import izumi.fundamentals.platform.functional.Identity trait MkInjector { def mkInjector(): Injector[Identity] = Injector.Standard() - def mkNoCglibInjector(): Injector[Identity] = Injector.NoProxies() + def mkNoProxiesInjector(): Injector[Identity] = Injector.NoProxies() def mkNoCyclesInjector(): Injector[Identity] = Injector.NoCycles() } diff --git a/distage/distage-extension-config/src/test/scala/izumi/distage/impl/OptionalDependencyTest.scala b/distage/distage-extension-config/src/test/scala/izumi/distage/impl/OptionalDependencyTest.scala index e70ec9f75e..32ea9aa4c6 100644 --- a/distage/distage-extension-config/src/test/scala/izumi/distage/impl/OptionalDependencyTest.scala +++ b/distage/distage-extension-config/src/test/scala/izumi/distage/impl/OptionalDependencyTest.scala @@ -137,8 +137,12 @@ class OptionalDependencyTest extends AnyWordSpec with GivenWhenThen { """) And("Methods that use `No More Orphans` trick can be called with nulls, but will error") - intercept[NoClassDefFoundError] { + intercept[Throwable] { QuasiIO.fromCats[Option, Lifecycle[_[_], Int]](null, null) + } match { + case _: NoClassDefFoundError => + case _: NullPointerException => + fail("NPE has been thrown, seems like cats are in the classpath (running under IDEA?)") } And("Methods that mention cats types only in generics will error on call") From b886ba67774a95569c3ff5273b3e06f0e8b19ab3 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Tue, 31 May 2022 18:04:53 +0100 Subject: [PATCH 2/6] kinda working bytebuddy proxy generator --- .jvmopts | 2 +- build.sbt | 134 +++++++++++++++++- .../CglibAtomicRefDispatcher.scala | 33 +++++ .../CglibNullMethodInterceptor.scala | 19 +++ .../bytebuddyproxy/DistageProxy.scala | 5 + .../bytebuddyproxy/DynamicProxyProvider.scala | 57 ++++++++ .../src/test/scala/izumi/.keep | 0 .../cglib/DynamicProxyProvider.scala | 6 +- .../CgLibInstantiationOpException.scala | 8 -- .../bootstrap/DynamicProxyBootstrap.scala | 3 +- project/Deps.sc | 13 +- project/Versions.scala | 1 + 12 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala create mode 100644 distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala create mode 100644 distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala create mode 100644 distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala create mode 100644 distage/distage-core-proxy-bytebuddy/src/test/scala/izumi/.keep delete mode 100644 distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/exceptions/CgLibInstantiationOpException.scala diff --git a/.jvmopts b/.jvmopts index 78bfdd705e..69d24bc5b1 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,4 +1,4 @@ --Xmx3G +-Xmx12G -XX:ReservedCodeCacheSize=256M -XX:MaxMetaspaceSize=2560M diff --git a/build.sbt b/build.sbt index 118c72c0d2..2030d56985 100644 --- a/build.sbt +++ b/build.sbt @@ -1503,10 +1503,139 @@ lazy val `distage-core-proxy-cglib` = project.in(file("distage/distage-core-prox ) .disablePlugins(AssemblyPlugin) +lazy val `distage-core-proxy-bytebuddy` = project.in(file("distage/distage-core-proxy-bytebuddy")) + .dependsOn( + `distage-core-api` % "test->compile;compile->compile" + ) + .settings( + libraryDependencies ++= Seq( + compilerPlugin("org.typelevel" % "kind-projector" % V.kind_projector cross CrossVersion.full), + "org.scala-lang.modules" %% "scala-collection-compat" % V.collection_compat, + "org.scalatest" %% "scalatest" % V.scalatest % Test, + "net.bytebuddy" % "byte-buddy" % V.bytebuddy + ) + ) + .settings( + crossScalaVersions := Seq( + "2.13.8", + "2.12.15" + ), + scalaVersion := crossScalaVersions.value.head, + organization := "io.7mind.izumi", + Compile / unmanagedSourceDirectories += baseDirectory.value / ".jvm/src/main/scala" , + Compile / unmanagedSourceDirectories ++= (scalaBinaryVersion.value :: CrossVersion.partialVersion(scalaVersion.value).toList.map(_._1)) + .map(v => baseDirectory.value / s".jvm/src/main/scala-$v").distinct, + Compile / unmanagedResourceDirectories += baseDirectory.value / ".jvm/src/main/resources" , + Test / unmanagedSourceDirectories += baseDirectory.value / ".jvm/src/test/scala" , + Test / unmanagedSourceDirectories ++= (scalaBinaryVersion.value :: CrossVersion.partialVersion(scalaVersion.value).toList.map(_._1)) + .map(v => baseDirectory.value / s".jvm/src/test/scala-$v").distinct, + Test / unmanagedResourceDirectories += baseDirectory.value / ".jvm/src/test/resources" , + scalacOptions ++= Seq( + s"-Xmacro-settings:product-name=${name.value}", + s"-Xmacro-settings:product-version=${version.value}", + s"-Xmacro-settings:product-group=${organization.value}", + s"-Xmacro-settings:scala-version=${scalaVersion.value}", + s"-Xmacro-settings:scala-versions=${crossScalaVersions.value.mkString(":")}" + ), + Test / testOptions += Tests.Argument("-oDF"), + scalacOptions += "-Wconf:any:error", + scalacOptions ++= { (isSnapshot.value, scalaVersion.value) match { + case (_, "2.12.15") => Seq( + "-target:jvm-1.8", + "-explaintypes", + "-Xsource:3", + "-P:kind-projector:underscore-placeholders", + "-Ypartial-unification", + if (insideCI.value) "-Wconf:any:error" else "-Wconf:any:warning", + "-Wconf:cat=optimizer:warning", + "-Wconf:cat=other-match-analysis:error", + "-Ybackend-parallelism", + math.min(16, math.max(1, sys.runtime.availableProcessors() - 1)).toString, + "-Xlint:adapted-args", + "-Xlint:by-name-right-associative", + "-Xlint:constant", + "-Xlint:delayedinit-select", + "-Xlint:doc-detached", + "-Xlint:inaccessible", + "-Xlint:infer-any", + "-Xlint:missing-interpolator", + "-Xlint:nullary-override", + "-Xlint:nullary-unit", + "-Xlint:option-implicit", + "-Xlint:package-object-classes", + "-Xlint:poly-implicit-overload", + "-Xlint:private-shadow", + "-Xlint:stars-align", + "-Xlint:type-parameter-shadow", + "-Xlint:unsound-match", + "-opt-warnings:_", + "-Ywarn-extra-implicit", + "-Ywarn-unused:_", + "-Ywarn-adapted-args", + "-Ywarn-dead-code", + "-Ywarn-inaccessible", + "-Ywarn-infer-any", + "-Ywarn-nullary-override", + "-Ywarn-nullary-unit", + "-Ywarn-numeric-widen", + "-Ywarn-unused-import", + "-Ywarn-value-discard", + "-Ycache-plugin-class-loader:always", + "-Ycache-macro-class-loader:last-modified" + ) + case (_, "2.13.8") => Seq( + "-target:jvm-1.8", + "-explaintypes", + "-Xsource:3", + "-P:kind-projector:underscore-placeholders", + if (insideCI.value) "-Wconf:any:error" else "-Wconf:any:warning", + "-Wconf:cat=optimizer:warning", + "-Wconf:cat=other-match-analysis:error", + "-Vimplicits", + "-Vtype-diffs", + "-Ybackend-parallelism", + math.min(16, math.max(1, sys.runtime.availableProcessors() - 1)).toString, + "-Wdead-code", + "-Wextra-implicit", + "-Wnumeric-widen", + "-Woctal-literal", + "-Wvalue-discard", + "-Wunused:_", + "-Wmacros:after", + "-Ycache-plugin-class-loader:always", + "-Ycache-macro-class-loader:last-modified", + "-Wunused:-synthetics" + ) + case (_, _) => Seq.empty + } }, + scalacOptions -= "-Wconf:any:warning", + scalacOptions += "-Wconf:cat=deprecation:warning", + scalacOptions += "-Wconf:msg=nowarn:silent", + scalacOptions += "-Wconf:msg=parameter.value.x\\$4.in.anonymous.function.is.never.used:silent", + scalacOptions += "-Wconf:msg=package.object.inheritance:silent", + Compile / sbt.Keys.doc / scalacOptions -= "-Wconf:any:error", + scalacOptions ++= Seq( + s"-Xmacro-settings:scalatest-version=${V.scalatest}", + s"-Xmacro-settings:is-ci=${insideCI.value}" + ), + scalacOptions ++= { (isSnapshot.value, scalaVersion.value) match { + case (false, "2.12.15") => Seq( + "-opt:l:inline", + "-opt-inline-from:izumi.**" + ) + case (false, "2.13.8") => Seq( + "-opt:l:inline", + "-opt-inline-from:izumi.**" + ) + case (_, _) => Seq.empty + } } + ) + .disablePlugins(AssemblyPlugin) + lazy val `distage-core` = project.in(file("distage/distage-core")) .dependsOn( `distage-core-api` % "test->compile;compile->compile", - `distage-core-proxy-cglib` % "test->compile;compile->compile" + `distage-core-proxy-bytebuddy` % "test->compile" ) .settings( libraryDependencies ++= Seq( @@ -3290,6 +3419,7 @@ lazy val `microsite` = project.in(file("doc/microsite")) `fundamentals-literals` % "test->compile;compile->compile", `distage-core-api` % "test->compile;compile->compile", `distage-core-proxy-cglib` % "test->compile;compile->compile", + `distage-core-proxy-bytebuddy` % "test->compile;compile->compile", `distage-core` % "test->compile;compile->compile", `distage-extension-config` % "test->compile;compile->compile", `distage-extension-plugins` % "test->compile;compile->compile", @@ -3682,6 +3812,7 @@ lazy val `distage` = (project in file(".agg/distage-distage")) .aggregate( `distage-core-api`, `distage-core-proxy-cglib`, + `distage-core-proxy-bytebuddy`, `distage-core`, `distage-extension-config`, `distage-extension-plugins`, @@ -3706,6 +3837,7 @@ lazy val `distage-jvm` = (project in file(".agg/distage-distage-jvm")) .aggregate( `distage-core-api`, `distage-core-proxy-cglib`, + `distage-core-proxy-bytebuddy`, `distage-core`, `distage-extension-config`, `distage-extension-plugins`, diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala new file mode 100644 index 0000000000..9a83ac5e8c --- /dev/null +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala @@ -0,0 +1,33 @@ +package izumi.distage.provisioning.strategies.bytebuddyproxy + +import izumi.distage.model.provisioning.proxies.ProxyDispatcher.AtomicProxyDispatcher + +import java.lang.reflect.{InvocationHandler, Method} + +// dynamic dispatching is not optimal, uhu +private[distage] class CglibAtomicRefDispatcher( + nullProxy: AnyRef +) extends AtomicProxyDispatcher + with InvocationHandler { + override def invoke(o: scala.Any, method: Method, objects: Array[AnyRef]): AnyRef = { + val methodName = method.getName + if (methodName == "equals" && (method.getParameterTypes sameElements Array(classOf[AnyRef]))) { + objects.headOption match { + case Some(r: DistageProxy) => + Boolean.box(getRef() == r._distageProxyReference) + + case _ => + method.invoke(getRef(), objects: _*) + } + } else if (methodName == "_distageProxyReference" && method.getParameterCount == 0) { + getRef() + } else { + method.invoke(getRef(), objects: _*) + } + } + + @inline private[this] final def getRef(): AnyRef = { + val value = reference.get() + if (value ne null) value else nullProxy + } +} diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala new file mode 100644 index 0000000000..74204011d3 --- /dev/null +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala @@ -0,0 +1,19 @@ +package izumi.distage.provisioning.strategies.bytebuddyproxy + +import izumi.distage.model.exceptions.interpretation.MissingRefException +import izumi.distage.model.reflection.DIKey + +import java.lang.reflect.{InvocationHandler, Method} + +// we use this to be able to display something for uninitialized proxies +private[distage] class CglibNullMethodInterceptor( + key: DIKey +) extends InvocationHandler { + override def invoke(o: Any, method: Method, objects: Array[AnyRef]): AnyRef = { + if (method.getName == "toString" && method.getParameterCount == 0) { + s"__UninitializedProxy__:$key" + } else { + throw new MissingRefException(s"Proxy for $key is not yet initialized", Set(key), None) + } + } +} diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala new file mode 100644 index 0000000000..27b6cfa5b3 --- /dev/null +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala @@ -0,0 +1,5 @@ +package izumi.distage.provisioning.strategies.bytebuddyproxy + +trait DistageProxy { + def _distageProxyReference: AnyRef +} diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala new file mode 100644 index 0000000000..a7521a4b66 --- /dev/null +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala @@ -0,0 +1,57 @@ +package izumi.distage.provisioning.strategies.bytebuddyproxy + +import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException +import izumi.distage.model.provisioning.proxies.ProxyProvider +import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} +import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} +import izumi.distage.model.reflection.DIKey +import izumi.fundamentals.platform.exceptions.IzThrowable.* +import net.bytebuddy.ByteBuddy +import net.bytebuddy.implementation.InvocationHandlerAdapter + +import java.lang.reflect.InvocationHandler + +object DynamicProxyProvider extends ProxyProvider { + + override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = { + val nullDispatcher = new CglibNullMethodInterceptor(deferredKey) + val nullProxy = mkDynamic(nullDispatcher, proxyContext) + + val realDispatcher = new CglibAtomicRefDispatcher(nullProxy) + val realProxy = mkDynamic(realDispatcher, proxyContext) + + DeferredInit(realDispatcher, realProxy) + } + + private def mkDynamic(dispatcher: InvocationHandler, proxyContext: ProxyContext): AnyRef = { + val clazz = proxyContext.runtimeClass.asInstanceOf[Class[AnyRef]] + + val constructedProxyClass: Class[AnyRef] = new ByteBuddy() + .subclass(clazz) + .implement(classOf[DistageProxy]) + .intercept(InvocationHandlerAdapter.of(dispatcher)) + .make() + .load(clazz.getClassLoader) + .getLoaded.asInstanceOf[Class[AnyRef]] + + try { + proxyContext.params match { + case Empty => + constructedProxyClass.getDeclaredConstructor().newInstance() + case Params(types, values) => + val c = constructedProxyClass.getDeclaredConstructor(types: _*) + c.newInstance(values: _*) + } + } catch { + case f: Throwable => + throw new ProxyInstantiationException( + s"Failed to instantiate class with CGLib, make sure you don't dereference proxied parameters in constructors: " + + s"class=${proxyContext.runtimeClass}, params=${proxyContext.params}, exception=${f.stackTrace}", + clazz, + proxyContext.params, + proxyContext.op, + f, + ) + } + } +} diff --git a/distage/distage-core-proxy-bytebuddy/src/test/scala/izumi/.keep b/distage/distage-core-proxy-bytebuddy/src/test/scala/izumi/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala index 4b327b8a54..7ebc513fbd 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala +++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala @@ -1,11 +1,11 @@ package izumi.distage.provisioning.strategies.cglib +import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException import izumi.distage.model.provisioning.proxies.ProxyProvider import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} import izumi.distage.model.reflection.DIKey -import izumi.distage.provisioning.strategies.cglib.exceptions.CgLibInstantiationOpException -import izumi.fundamentals.platform.exceptions.IzThrowable._ +import izumi.fundamentals.platform.exceptions.IzThrowable.* import net.sf.cglib.proxy.{Callback, Enhancer} object DynamicProxyProvider extends ProxyProvider { @@ -46,7 +46,7 @@ object DynamicProxyProvider extends ProxyProvider { } } catch { case f: Throwable => - throw new CgLibInstantiationOpException( + throw new ProxyInstantiationException( s"Failed to instantiate class with CGLib, make sure you don't dereference proxied parameters in constructors: " + s"class=${proxyContext.runtimeClass}, params=${proxyContext.params}, exception=${f.stackTrace}", clazz, diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/exceptions/CgLibInstantiationOpException.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/exceptions/CgLibInstantiationOpException.scala deleted file mode 100644 index 45461a57f3..0000000000 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/exceptions/CgLibInstantiationOpException.scala +++ /dev/null @@ -1,8 +0,0 @@ -package izumi.distage.provisioning.strategies.cglib.exceptions - -import izumi.distage.model.exceptions.DIException -import izumi.distage.model.plan.ExecutableOp -import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams - -class CgLibInstantiationOpException(message: String, val target: Class[?], val params: ProxyParams, val op: ExecutableOp, cause: Throwable) - extends DIException(message, cause) diff --git a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala index 18110a3f2b..8af670fe68 100644 --- a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala +++ b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala @@ -7,7 +7,8 @@ import scala.util.Try object DynamicProxyBootstrap { - val dynProxyProviderName = "izumi.distage.provisioning.strategies.cglib.DynamicProxyProvider$" +// val dynProxyProviderName = "izumi.distage.provisioning.strategies.cglib.DynamicProxyProvider$" + val dynProxyProviderName = "izumi.distage.provisioning.strategies.bytebuddyproxy.DynamicProxyProvider$" val DynamicProxyProvider: ProxyProvider = Try(TypeUtil.instantiateObject[ProxyProvider](Class.forName(dynProxyProviderName))).toOption match { case Some(value) => diff --git a/project/Deps.sc b/project/Deps.sc index c134b71e72..5efc77fc01 100644 --- a/project/Deps.sc +++ b/project/Deps.sc @@ -29,6 +29,7 @@ object Izumi { val slf4j = Version.VExpr("V.slf4j") val typesafe_config = Version.VExpr("V.typesafe_config") val cglib_nodep = Version.VExpr("V.cglib_nodep") + val bytebuddy = Version.VExpr("V.bytebuddy") val scala_java_time = Version.VExpr("V.scala_java_time") val scalamock = Version.VExpr("V.scalamock") val docker_java = Version.VExpr("V.docker_java") @@ -102,6 +103,7 @@ object Izumi { final val scala_reflect = Library("org.scala-lang", "scala-reflect", Version.VExpr("scalaVersion.value"), LibraryType.Invariant) final val cglib_nodep = Library("cglib", "cglib-nodep", V.cglib_nodep, LibraryType.Invariant) in Scope.Compile.jvm + final val bytebuddy = Library("net.bytebuddy", "byte-buddy", V.bytebuddy, LibraryType.Invariant) in Scope.Compile.jvm final val projector = Library("org.typelevel", "kind-projector", V.kind_projector, LibraryType.Invariant) .more(LibSetting.Raw("cross CrossVersion.full")) @@ -292,6 +294,7 @@ object Izumi { final lazy val coreApi = ArtifactId("distage-core-api") final lazy val proxyCglib = ArtifactId("distage-core-proxy-cglib") + final lazy val proxyBytebuddy = ArtifactId("distage-core-proxy-bytebuddy") final lazy val core = ArtifactId("distage-core") final lazy val config = ArtifactId("distage-extension-config") final lazy val plugins = ArtifactId("distage-extension-plugins") @@ -453,11 +456,17 @@ object Izumi { depends = Seq(Projects.fundamentals.reflection, Projects.fundamentals.bio).map(_ in Scope.Compile.all), ), Artifact( - name = Projects.distage.proxyCglib, + name = Projects.distage.proxyCglib, // cglib doesn't work on modern java and is deprecated libs = Seq(cglib_nodep), depends = Seq(Projects.distage.coreApi).map(_ in Scope.Compile.all), platforms = Targets.jvm, ), + Artifact( + name = Projects.distage.proxyBytebuddy, + libs = Seq(bytebuddy), + depends = Seq(Projects.distage.coreApi).map(_ in Scope.Compile.all), + platforms = Targets.jvm, + ), Artifact( name = Projects.distage.core, libs = allMonadsOptional ++ Seq( @@ -466,7 +475,7 @@ object Izumi { scala_java_time in Scope.Test.js, javaXInject in Scope.Test.all, ), - depends = Seq(Projects.distage.coreApi in Scope.Compile.all, Projects.distage.proxyCglib in Scope.Compile.jvm), + depends = Seq(Projects.distage.coreApi in Scope.Compile.all, Projects.distage.proxyBytebuddy in Scope.Test.jvm), ), Artifact( name = Projects.distage.config, diff --git a/project/Versions.scala b/project/Versions.scala index 96d0f98149..185cbc5ed0 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -37,6 +37,7 @@ object V { // good to drop - java val cglib_nodep = "3.3.0" + val bytebuddy = "1.12.10" val docker_java = "3.2.13" // microsite-only From b0dba057b5e22997b9326417e494ad3c1615eefd Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Tue, 31 May 2022 18:37:56 +0100 Subject: [PATCH 3/6] working bb --- .../provisioning/proxies}/DistageProxy.scala | 2 +- ...ala => ByteBuddyAtomicRefDispatcher.scala} | 13 +++++++------ ...a => ByteBuddyNullMethodInterceptor.scala} | 2 +- .../bytebuddyproxy/DistageProxy.scala | 5 ----- .../bytebuddyproxy/DynamicProxyProvider.scala | 12 ++++++++---- .../CglibAtomicRefDispatcher.scala | 5 +++-- .../CglibNullMethodInterceptor.scala | 2 +- .../DynamicProxyProvider.scala | 4 ++-- .../izumi/distage/gc/GcBasicTestsJvm.scala | 19 +++++++++++++++---- .../test/scala/izumi/distage/gc/GcCases.scala | 4 +++- 10 files changed, 41 insertions(+), 27 deletions(-) rename distage/{distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib => distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies}/DistageProxy.scala (53%) rename distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/{CglibAtomicRefDispatcher.scala => ByteBuddyAtomicRefDispatcher.scala} (72%) rename distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/{CglibNullMethodInterceptor.scala => ByteBuddyNullMethodInterceptor.scala} (92%) delete mode 100644 distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala rename distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/{cglib => cglibproxy}/CglibAtomicRefDispatcher.scala (90%) rename distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/{cglib => cglibproxy}/CglibNullMethodInterceptor.scala (92%) rename distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/{cglib => cglibproxy}/DynamicProxyProvider.scala (93%) diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DistageProxy.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/DistageProxy.scala similarity index 53% rename from distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DistageProxy.scala rename to distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/DistageProxy.scala index b3cfb6bf49..f0a00c1c51 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DistageProxy.scala +++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/DistageProxy.scala @@ -1,4 +1,4 @@ -package izumi.distage.provisioning.strategies.cglib +package izumi.distage.model.provisioning.proxies trait DistageProxy { def _distageProxyReference: AnyRef diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/ByteBuddyAtomicRefDispatcher.scala similarity index 72% rename from distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala rename to distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/ByteBuddyAtomicRefDispatcher.scala index 9a83ac5e8c..2b29368554 100644 --- a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibAtomicRefDispatcher.scala +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/ByteBuddyAtomicRefDispatcher.scala @@ -1,11 +1,12 @@ package izumi.distage.provisioning.strategies.bytebuddyproxy +import izumi.distage.model.provisioning.proxies.DistageProxy import izumi.distage.model.provisioning.proxies.ProxyDispatcher.AtomicProxyDispatcher import java.lang.reflect.{InvocationHandler, Method} // dynamic dispatching is not optimal, uhu -private[distage] class CglibAtomicRefDispatcher( +private[distage] class ByteBuddyAtomicRefDispatcher( nullProxy: AnyRef ) extends AtomicProxyDispatcher with InvocationHandler { @@ -14,19 +15,19 @@ private[distage] class CglibAtomicRefDispatcher( if (methodName == "equals" && (method.getParameterTypes sameElements Array(classOf[AnyRef]))) { objects.headOption match { case Some(r: DistageProxy) => - Boolean.box(getRef() == r._distageProxyReference) + Boolean.box(getRef == r._distageProxyReference) case _ => - method.invoke(getRef(), objects: _*) + method.invoke(getRef, objects: _*) } } else if (methodName == "_distageProxyReference" && method.getParameterCount == 0) { - getRef() + getRef } else { - method.invoke(getRef(), objects: _*) + method.invoke(getRef, objects: _*) } } - @inline private[this] final def getRef(): AnyRef = { + @inline private[this] final def getRef: AnyRef = { val value = reference.get() if (value ne null) value else nullProxy } diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/ByteBuddyNullMethodInterceptor.scala similarity index 92% rename from distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala rename to distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/ByteBuddyNullMethodInterceptor.scala index 74204011d3..58faffa650 100644 --- a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/CglibNullMethodInterceptor.scala +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/ByteBuddyNullMethodInterceptor.scala @@ -6,7 +6,7 @@ import izumi.distage.model.reflection.DIKey import java.lang.reflect.{InvocationHandler, Method} // we use this to be able to display something for uninitialized proxies -private[distage] class CglibNullMethodInterceptor( +private[distage] class ByteBuddyNullMethodInterceptor( key: DIKey ) extends InvocationHandler { override def invoke(o: Any, method: Method, objects: Array[AnyRef]): AnyRef = { diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala deleted file mode 100644 index 27b6cfa5b3..0000000000 --- a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DistageProxy.scala +++ /dev/null @@ -1,5 +0,0 @@ -package izumi.distage.provisioning.strategies.bytebuddyproxy - -trait DistageProxy { - def _distageProxyReference: AnyRef -} diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala index a7521a4b66..747834758f 100644 --- a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala @@ -1,23 +1,25 @@ package izumi.distage.provisioning.strategies.bytebuddyproxy import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException -import izumi.distage.model.provisioning.proxies.ProxyProvider +import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} import izumi.distage.model.reflection.DIKey import izumi.fundamentals.platform.exceptions.IzThrowable.* import net.bytebuddy.ByteBuddy +import net.bytebuddy.dynamic.scaffold.TypeValidation import net.bytebuddy.implementation.InvocationHandlerAdapter +import net.bytebuddy.matcher.ElementMatchers import java.lang.reflect.InvocationHandler object DynamicProxyProvider extends ProxyProvider { override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = { - val nullDispatcher = new CglibNullMethodInterceptor(deferredKey) + val nullDispatcher = new ByteBuddyNullMethodInterceptor(deferredKey) val nullProxy = mkDynamic(nullDispatcher, proxyContext) - val realDispatcher = new CglibAtomicRefDispatcher(nullProxy) + val realDispatcher = new ByteBuddyAtomicRefDispatcher(nullProxy) val realProxy = mkDynamic(realDispatcher, proxyContext) DeferredInit(realDispatcher, realProxy) @@ -27,9 +29,11 @@ object DynamicProxyProvider extends ProxyProvider { val clazz = proxyContext.runtimeClass.asInstanceOf[Class[AnyRef]] val constructedProxyClass: Class[AnyRef] = new ByteBuddy() + .`with`(TypeValidation.DISABLED) .subclass(clazz) - .implement(classOf[DistageProxy]) + .method(ElementMatchers.isMethod) .intercept(InvocationHandlerAdapter.of(dispatcher)) + .implement(classOf[DistageProxy]) .make() .load(clazz.getClassLoader) .getLoaded.asInstanceOf[Class[AnyRef]] diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibAtomicRefDispatcher.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala similarity index 90% rename from distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibAtomicRefDispatcher.scala rename to distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala index d5d57be543..51aac713e8 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibAtomicRefDispatcher.scala +++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala @@ -1,7 +1,8 @@ -package izumi.distage.provisioning.strategies.cglib +package izumi.distage.provisioning.strategies.cglibproxy -import java.lang.reflect.Method +import izumi.distage.model.provisioning.proxies.DistageProxy +import java.lang.reflect.Method import izumi.distage.model.provisioning.proxies.ProxyDispatcher.AtomicProxyDispatcher import net.sf.cglib.proxy.{MethodInterceptor, MethodProxy} diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala similarity index 92% rename from distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala rename to distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala index da1c6b657e..930e51a87a 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala +++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala @@ -1,4 +1,4 @@ -package izumi.distage.provisioning.strategies.cglib +package izumi.distage.provisioning.strategies.cglibproxy import izumi.distage.model.exceptions.interpretation.MissingRefException diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/DynamicProxyProvider.scala similarity index 93% rename from distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala rename to distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/DynamicProxyProvider.scala index 7ebc513fbd..c2a50dc228 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/DynamicProxyProvider.scala +++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/DynamicProxyProvider.scala @@ -1,7 +1,7 @@ -package izumi.distage.provisioning.strategies.cglib +package izumi.distage.provisioning.strategies.cglibproxy import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException -import izumi.distage.model.provisioning.proxies.ProxyProvider +import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} import izumi.distage.model.reflection.DIKey diff --git a/distage/distage-core/.jvm/src/test/scala/izumi/distage/gc/GcBasicTestsJvm.scala b/distage/distage-core/.jvm/src/test/scala/izumi/distage/gc/GcBasicTestsJvm.scala index 2c04766676..a7e8a9a06b 100644 --- a/distage/distage-core/.jvm/src/test/scala/izumi/distage/gc/GcBasicTestsJvm.scala +++ b/distage/distage-core/.jvm/src/test/scala/izumi/distage/gc/GcBasicTestsJvm.scala @@ -4,6 +4,7 @@ import distage.DIKey import izumi.distage.model.PlannerInput import izumi.distage.model.definition.{Activation, ModuleDef} import izumi.distage.model.plan.Roots +import izumi.distage.model.provisioning.proxies.DistageProxy import org.scalatest.wordspec.AnyWordSpec import scala.collection.immutable @@ -30,10 +31,20 @@ class GcBasicTestsJvm extends AnyWordSpec with MkGcInjector { val result = injector.produce(plan).unsafeGet() assert(result.find[Trash].isEmpty) - assert(result.get[Circular1].c2 != null) - assert(result.get[Circular2].c1 != null) - assert(result.get[Circular1].c2.isInstanceOf[Circular2]) - assert(result.get[Circular2].c1.isInstanceOf[Circular1]) + val c1 = result.get[Circular1] + val c2 = result.get[Circular2] + + assert(c1.c2 != null) + assert(c2.c1 != null) + + assert(c2.test == 1) + + assert(c1.c2.isInstanceOf[Circular2]) + assert(c2.c1.isInstanceOf[Circular1]) + + assert(c2.isInstanceOf[DistageProxy] || c1.isInstanceOf[DistageProxy]) + val p = List(c1, c2).collect { case p: DistageProxy => p } + assert(p.forall(_._distageProxyReference != null)) } "keep by-name loops alive" in { diff --git a/distage/distage-core/src/test/scala/izumi/distage/gc/GcCases.scala b/distage/distage-core/src/test/scala/izumi/distage/gc/GcCases.scala index 05240b3bb2..821263b309 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/gc/GcCases.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/gc/GcCases.scala @@ -11,7 +11,9 @@ object GcCases { class Circular1(val c2: Circular2) - class Circular2(val c1: Circular1, val c4: Circular4) + class Circular2(val c1: Circular1, val c4: Circular4) { + def test: Int = 1 + } class Circular3(val c4: Circular4) From 648a2136c4584b27e71b70eb13f86bf455896f72 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Tue, 31 May 2022 18:44:30 +0100 Subject: [PATCH 4/6] better dynamic loading --- .../DynamicProxyProvider.scala | 7 ++++--- .../DynamicProxyProvider.scala | 6 +++--- .../izumi/distage/bootstrap/DynamicProxyBootstrap.scala | 3 +-- 3 files changed, 8 insertions(+), 8 deletions(-) rename distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/{bytebuddyproxy => dynamicproxy}/DynamicProxyProvider.scala (92%) rename distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/{cglibproxy => dynamicproxy}/DynamicProxyProvider.scala (92%) diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala similarity index 92% rename from distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala rename to distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala index 747834758f..b188e5d4c5 100644 --- a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/bytebuddyproxy/DynamicProxyProvider.scala +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala @@ -1,15 +1,16 @@ -package izumi.distage.provisioning.strategies.bytebuddyproxy +package izumi.distage.provisioning.strategies.dynamicproxy import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException -import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} +import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} import izumi.distage.model.reflection.DIKey -import izumi.fundamentals.platform.exceptions.IzThrowable.* +import izumi.distage.provisioning.strategies.bytebuddyproxy.{ByteBuddyAtomicRefDispatcher, ByteBuddyNullMethodInterceptor} import net.bytebuddy.ByteBuddy import net.bytebuddy.dynamic.scaffold.TypeValidation import net.bytebuddy.implementation.InvocationHandlerAdapter import net.bytebuddy.matcher.ElementMatchers +import izumi.fundamentals.platform.exceptions.IzThrowable.* import java.lang.reflect.InvocationHandler diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/DynamicProxyProvider.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala similarity index 92% rename from distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/DynamicProxyProvider.scala rename to distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala index c2a50dc228..8f9ce3aaca 100644 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/DynamicProxyProvider.scala +++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala @@ -1,11 +1,11 @@ -package izumi.distage.provisioning.strategies.cglibproxy +package izumi.distage.provisioning.strategies.dynamicproxy import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException -import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} +import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} import izumi.distage.model.reflection.DIKey -import izumi.fundamentals.platform.exceptions.IzThrowable.* +import izumi.distage.provisioning.strategies.cglibproxy.{CglibAtomicRefDispatcher, CglibNullMethodInterceptor} import net.sf.cglib.proxy.{Callback, Enhancer} object DynamicProxyProvider extends ProxyProvider { diff --git a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala index 8af670fe68..99183c0935 100644 --- a/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala +++ b/distage/distage-core/.jvm/src/main/scala/izumi/distage/bootstrap/DynamicProxyBootstrap.scala @@ -6,9 +6,8 @@ import izumi.fundamentals.reflection.TypeUtil import scala.util.Try object DynamicProxyBootstrap { + val dynProxyProviderName = "izumi.distage.provisioning.strategies.dynamicproxy.DynamicProxyProvider$" -// val dynProxyProviderName = "izumi.distage.provisioning.strategies.cglib.DynamicProxyProvider$" - val dynProxyProviderName = "izumi.distage.provisioning.strategies.bytebuddyproxy.DynamicProxyProvider$" val DynamicProxyProvider: ProxyProvider = Try(TypeUtil.instantiateObject[ProxyProvider](Class.forName(dynProxyProviderName))).toOption match { case Some(value) => From 8673f06389290f3ce9818944c1cc19b2db252f64 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Tue, 31 May 2022 18:50:37 +0100 Subject: [PATCH 5/6] 2.12 fixes, cglib removed --- build.sbt | 132 ------------------ .../dynamicproxy/DynamicProxyProvider.scala | 7 +- project/Deps.sc | 9 -- project/Versions.scala | 1 - 4 files changed, 4 insertions(+), 145 deletions(-) diff --git a/build.sbt b/build.sbt index 2030d56985..6e1a888196 100644 --- a/build.sbt +++ b/build.sbt @@ -1374,135 +1374,6 @@ lazy val `distage-core-api` = project.in(file("distage/distage-core-api")) ) .disablePlugins(AssemblyPlugin) -lazy val `distage-core-proxy-cglib` = project.in(file("distage/distage-core-proxy-cglib")) - .dependsOn( - `distage-core-api` % "test->compile;compile->compile" - ) - .settings( - libraryDependencies ++= Seq( - compilerPlugin("org.typelevel" % "kind-projector" % V.kind_projector cross CrossVersion.full), - "org.scala-lang.modules" %% "scala-collection-compat" % V.collection_compat, - "org.scalatest" %% "scalatest" % V.scalatest % Test, - "cglib" % "cglib-nodep" % V.cglib_nodep - ) - ) - .settings( - crossScalaVersions := Seq( - "2.13.8", - "2.12.15" - ), - scalaVersion := crossScalaVersions.value.head, - organization := "io.7mind.izumi", - Compile / unmanagedSourceDirectories += baseDirectory.value / ".jvm/src/main/scala" , - Compile / unmanagedSourceDirectories ++= (scalaBinaryVersion.value :: CrossVersion.partialVersion(scalaVersion.value).toList.map(_._1)) - .map(v => baseDirectory.value / s".jvm/src/main/scala-$v").distinct, - Compile / unmanagedResourceDirectories += baseDirectory.value / ".jvm/src/main/resources" , - Test / unmanagedSourceDirectories += baseDirectory.value / ".jvm/src/test/scala" , - Test / unmanagedSourceDirectories ++= (scalaBinaryVersion.value :: CrossVersion.partialVersion(scalaVersion.value).toList.map(_._1)) - .map(v => baseDirectory.value / s".jvm/src/test/scala-$v").distinct, - Test / unmanagedResourceDirectories += baseDirectory.value / ".jvm/src/test/resources" , - scalacOptions ++= Seq( - s"-Xmacro-settings:product-name=${name.value}", - s"-Xmacro-settings:product-version=${version.value}", - s"-Xmacro-settings:product-group=${organization.value}", - s"-Xmacro-settings:scala-version=${scalaVersion.value}", - s"-Xmacro-settings:scala-versions=${crossScalaVersions.value.mkString(":")}" - ), - Test / testOptions += Tests.Argument("-oDF"), - scalacOptions += "-Wconf:any:error", - scalacOptions ++= { (isSnapshot.value, scalaVersion.value) match { - case (_, "2.12.15") => Seq( - "-target:jvm-1.8", - "-explaintypes", - "-Xsource:3", - "-P:kind-projector:underscore-placeholders", - "-Ypartial-unification", - if (insideCI.value) "-Wconf:any:error" else "-Wconf:any:warning", - "-Wconf:cat=optimizer:warning", - "-Wconf:cat=other-match-analysis:error", - "-Ybackend-parallelism", - math.min(16, math.max(1, sys.runtime.availableProcessors() - 1)).toString, - "-Xlint:adapted-args", - "-Xlint:by-name-right-associative", - "-Xlint:constant", - "-Xlint:delayedinit-select", - "-Xlint:doc-detached", - "-Xlint:inaccessible", - "-Xlint:infer-any", - "-Xlint:missing-interpolator", - "-Xlint:nullary-override", - "-Xlint:nullary-unit", - "-Xlint:option-implicit", - "-Xlint:package-object-classes", - "-Xlint:poly-implicit-overload", - "-Xlint:private-shadow", - "-Xlint:stars-align", - "-Xlint:type-parameter-shadow", - "-Xlint:unsound-match", - "-opt-warnings:_", - "-Ywarn-extra-implicit", - "-Ywarn-unused:_", - "-Ywarn-adapted-args", - "-Ywarn-dead-code", - "-Ywarn-inaccessible", - "-Ywarn-infer-any", - "-Ywarn-nullary-override", - "-Ywarn-nullary-unit", - "-Ywarn-numeric-widen", - "-Ywarn-unused-import", - "-Ywarn-value-discard", - "-Ycache-plugin-class-loader:always", - "-Ycache-macro-class-loader:last-modified" - ) - case (_, "2.13.8") => Seq( - "-target:jvm-1.8", - "-explaintypes", - "-Xsource:3", - "-P:kind-projector:underscore-placeholders", - if (insideCI.value) "-Wconf:any:error" else "-Wconf:any:warning", - "-Wconf:cat=optimizer:warning", - "-Wconf:cat=other-match-analysis:error", - "-Vimplicits", - "-Vtype-diffs", - "-Ybackend-parallelism", - math.min(16, math.max(1, sys.runtime.availableProcessors() - 1)).toString, - "-Wdead-code", - "-Wextra-implicit", - "-Wnumeric-widen", - "-Woctal-literal", - "-Wvalue-discard", - "-Wunused:_", - "-Wmacros:after", - "-Ycache-plugin-class-loader:always", - "-Ycache-macro-class-loader:last-modified", - "-Wunused:-synthetics" - ) - case (_, _) => Seq.empty - } }, - scalacOptions -= "-Wconf:any:warning", - scalacOptions += "-Wconf:cat=deprecation:warning", - scalacOptions += "-Wconf:msg=nowarn:silent", - scalacOptions += "-Wconf:msg=parameter.value.x\\$4.in.anonymous.function.is.never.used:silent", - scalacOptions += "-Wconf:msg=package.object.inheritance:silent", - Compile / sbt.Keys.doc / scalacOptions -= "-Wconf:any:error", - scalacOptions ++= Seq( - s"-Xmacro-settings:scalatest-version=${V.scalatest}", - s"-Xmacro-settings:is-ci=${insideCI.value}" - ), - scalacOptions ++= { (isSnapshot.value, scalaVersion.value) match { - case (false, "2.12.15") => Seq( - "-opt:l:inline", - "-opt-inline-from:izumi.**" - ) - case (false, "2.13.8") => Seq( - "-opt:l:inline", - "-opt-inline-from:izumi.**" - ) - case (_, _) => Seq.empty - } } - ) - .disablePlugins(AssemblyPlugin) - lazy val `distage-core-proxy-bytebuddy` = project.in(file("distage/distage-core-proxy-bytebuddy")) .dependsOn( `distage-core-api` % "test->compile;compile->compile" @@ -3418,7 +3289,6 @@ lazy val `microsite` = project.in(file("doc/microsite")) `fundamentals-orphans` % "test->compile;compile->compile", `fundamentals-literals` % "test->compile;compile->compile", `distage-core-api` % "test->compile;compile->compile", - `distage-core-proxy-cglib` % "test->compile;compile->compile", `distage-core-proxy-bytebuddy` % "test->compile;compile->compile", `distage-core` % "test->compile;compile->compile", `distage-extension-config` % "test->compile;compile->compile", @@ -3811,7 +3681,6 @@ lazy val `distage` = (project in file(".agg/distage-distage")) .disablePlugins(AssemblyPlugin) .aggregate( `distage-core-api`, - `distage-core-proxy-cglib`, `distage-core-proxy-bytebuddy`, `distage-core`, `distage-extension-config`, @@ -3836,7 +3705,6 @@ lazy val `distage-jvm` = (project in file(".agg/distage-distage-jvm")) .disablePlugins(AssemblyPlugin) .aggregate( `distage-core-api`, - `distage-core-proxy-cglib`, `distage-core-proxy-bytebuddy`, `distage-core`, `distage-extension-config`, diff --git a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala index b188e5d4c5..1b416809d9 100644 --- a/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala +++ b/distage/distage-core-proxy-bytebuddy/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala @@ -9,8 +9,9 @@ import izumi.distage.provisioning.strategies.bytebuddyproxy.{ByteBuddyAtomicRefD import net.bytebuddy.ByteBuddy import net.bytebuddy.dynamic.scaffold.TypeValidation import net.bytebuddy.implementation.InvocationHandlerAdapter -import net.bytebuddy.matcher.ElementMatchers +import net.bytebuddy.matcher.{ElementMatcher, ElementMatchers} import izumi.fundamentals.platform.exceptions.IzThrowable.* +import net.bytebuddy.description.method.MethodDescription import java.lang.reflect.InvocationHandler @@ -32,7 +33,7 @@ object DynamicProxyProvider extends ProxyProvider { val constructedProxyClass: Class[AnyRef] = new ByteBuddy() .`with`(TypeValidation.DISABLED) .subclass(clazz) - .method(ElementMatchers.isMethod) + .method(ElementMatchers.isMethod.asInstanceOf[ElementMatcher[MethodDescription]]) .intercept(InvocationHandlerAdapter.of(dispatcher)) .implement(classOf[DistageProxy]) .make() @@ -45,7 +46,7 @@ object DynamicProxyProvider extends ProxyProvider { constructedProxyClass.getDeclaredConstructor().newInstance() case Params(types, values) => val c = constructedProxyClass.getDeclaredConstructor(types: _*) - c.newInstance(values: _*) + c.newInstance(values.map(_.asInstanceOf[AnyRef]): _*) } } catch { case f: Throwable => diff --git a/project/Deps.sc b/project/Deps.sc index 5efc77fc01..aba682d890 100644 --- a/project/Deps.sc +++ b/project/Deps.sc @@ -28,7 +28,6 @@ object Izumi { val classgraph = Version.VExpr("V.classgraph") val slf4j = Version.VExpr("V.slf4j") val typesafe_config = Version.VExpr("V.typesafe_config") - val cglib_nodep = Version.VExpr("V.cglib_nodep") val bytebuddy = Version.VExpr("V.bytebuddy") val scala_java_time = Version.VExpr("V.scala_java_time") val scalamock = Version.VExpr("V.scalamock") @@ -102,7 +101,6 @@ object Izumi { final val scala_library = Library("org.scala-lang", "scala-library", Version.VExpr("scalaVersion.value"), LibraryType.Invariant) final val scala_reflect = Library("org.scala-lang", "scala-reflect", Version.VExpr("scalaVersion.value"), LibraryType.Invariant) - final val cglib_nodep = Library("cglib", "cglib-nodep", V.cglib_nodep, LibraryType.Invariant) in Scope.Compile.jvm final val bytebuddy = Library("net.bytebuddy", "byte-buddy", V.bytebuddy, LibraryType.Invariant) in Scope.Compile.jvm final val projector = Library("org.typelevel", "kind-projector", V.kind_projector, LibraryType.Invariant) @@ -293,7 +291,6 @@ object Izumi { final val basePath = Seq("distage") final lazy val coreApi = ArtifactId("distage-core-api") - final lazy val proxyCglib = ArtifactId("distage-core-proxy-cglib") final lazy val proxyBytebuddy = ArtifactId("distage-core-proxy-bytebuddy") final lazy val core = ArtifactId("distage-core") final lazy val config = ArtifactId("distage-extension-config") @@ -455,12 +452,6 @@ object Izumi { libs = allCatsOptional ++ allZioOptional ++ allMonadsTest ++ Seq(scala_reflect in Scope.Provided.all), depends = Seq(Projects.fundamentals.reflection, Projects.fundamentals.bio).map(_ in Scope.Compile.all), ), - Artifact( - name = Projects.distage.proxyCglib, // cglib doesn't work on modern java and is deprecated - libs = Seq(cglib_nodep), - depends = Seq(Projects.distage.coreApi).map(_ in Scope.Compile.all), - platforms = Targets.jvm, - ), Artifact( name = Projects.distage.proxyBytebuddy, libs = Seq(bytebuddy), diff --git a/project/Versions.scala b/project/Versions.scala index 185cbc5ed0..0d59b17159 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -36,7 +36,6 @@ object V { val typesafe_config = "1.4.0" // good to drop - java - val cglib_nodep = "3.3.0" val bytebuddy = "1.12.10" val docker_java = "3.2.13" From 8a0cc00f54004bb40639b3ac34674cf7d4540104 Mon Sep 17 00:00:00 2001 From: Pavel Shirshov Date: Tue, 31 May 2022 18:51:40 +0100 Subject: [PATCH 6/6] cglib removed --- .../cglibproxy/CglibAtomicRefDispatcher.scala | 36 ----------- .../CglibNullMethodInterceptor.scala | 20 ------- .../dynamicproxy/DynamicProxyProvider.scala | 59 ------------------- .../src/test/scala/izumi/.keep | 0 4 files changed, 115 deletions(-) delete mode 100644 distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala delete mode 100644 distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala delete mode 100644 distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala delete mode 100644 distage/distage-core-proxy-cglib/src/test/scala/izumi/.keep diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala deleted file mode 100644 index 51aac713e8..0000000000 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibAtomicRefDispatcher.scala +++ /dev/null @@ -1,36 +0,0 @@ -package izumi.distage.provisioning.strategies.cglibproxy - -import izumi.distage.model.provisioning.proxies.DistageProxy - -import java.lang.reflect.Method -import izumi.distage.model.provisioning.proxies.ProxyDispatcher.AtomicProxyDispatcher -import net.sf.cglib.proxy.{MethodInterceptor, MethodProxy} - -// dynamic dispatching is not optimal, uhu -private[distage] class CglibAtomicRefDispatcher( - nullProxy: AnyRef -) extends AtomicProxyDispatcher - with MethodInterceptor { - - override def intercept(o: scala.Any, method: Method, objects: Array[AnyRef], methodProxy: MethodProxy): AnyRef = { - val methodName = method.getName - if (methodName == "equals" && (method.getParameterTypes sameElements Array(classOf[AnyRef]))) { - objects.headOption match { - case Some(r: DistageProxy) => - Boolean.box(getRef() == r._distageProxyReference) - - case _ => - method.invoke(getRef(), objects: _*) - } - } else if (methodName == "_distageProxyReference" && method.getParameterCount == 0) { - getRef() - } else { - method.invoke(getRef(), objects: _*) - } - } - - @inline private[this] final def getRef(): AnyRef = { - val value = reference.get() - if (value ne null) value else nullProxy - } -} diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala deleted file mode 100644 index 930e51a87a..0000000000 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglibproxy/CglibNullMethodInterceptor.scala +++ /dev/null @@ -1,20 +0,0 @@ -package izumi.distage.provisioning.strategies.cglibproxy - -import izumi.distage.model.exceptions.interpretation.MissingRefException - -import java.lang.reflect.Method -import izumi.distage.model.reflection.DIKey -import net.sf.cglib.proxy.{MethodInterceptor, MethodProxy} - -// we use this to be able to display something for uninitialized proxies -private[distage] class CglibNullMethodInterceptor( - key: DIKey -) extends MethodInterceptor { - override def intercept(o: Any, method: Method, objects: Array[AnyRef], methodProxy: MethodProxy): AnyRef = { - if (method.getName == "toString" && method.getParameterCount == 0) { - s"__UninitializedProxy__:$key" - } else { - throw new MissingRefException(s"Proxy for $key is not yet initialized", Set(key), None) - } - } -} diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala deleted file mode 100644 index 8f9ce3aaca..0000000000 --- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/dynamicproxy/DynamicProxyProvider.scala +++ /dev/null @@ -1,59 +0,0 @@ -package izumi.distage.provisioning.strategies.dynamicproxy - -import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException -import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params} -import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext} -import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider} -import izumi.distage.model.reflection.DIKey -import izumi.distage.provisioning.strategies.cglibproxy.{CglibAtomicRefDispatcher, CglibNullMethodInterceptor} -import net.sf.cglib.proxy.{Callback, Enhancer} - -object DynamicProxyProvider extends ProxyProvider { - - override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = { - val nullDispatcher = new CglibNullMethodInterceptor(deferredKey) - val nullProxy = mkDynamic(nullDispatcher, proxyContext) - - val realDispatcher = new CglibAtomicRefDispatcher(nullProxy) - val realProxy = mkDynamic(realDispatcher, proxyContext) - - DeferredInit(realDispatcher, realProxy) - } - - private def mkDynamic(dispatcher: Callback, proxyContext: ProxyContext): AnyRef = { - val clazz = proxyContext.runtimeClass - - // Enhancer.setSuperclass is side-effectful, so we had to copypaste - val enhancer = new Enhancer() - - if (clazz.isInterface) { - enhancer.setInterfaces(Array[Class[?]](clazz, classOf[DistageProxy])) - } else if (clazz == classOf[Any]) { - enhancer.setInterfaces(Array(classOf[DistageProxy])) - } else { - enhancer.setSuperclass(clazz) - enhancer.setInterfaces(Array(classOf[DistageProxy])) - } - - enhancer.setCallback(dispatcher) - - try { - proxyContext.params match { - case Empty => - enhancer.create() - case Params(types, values) => - enhancer.create(types, values.asInstanceOf[Array[Object]]) - } - } catch { - case f: Throwable => - throw new ProxyInstantiationException( - s"Failed to instantiate class with CGLib, make sure you don't dereference proxied parameters in constructors: " + - s"class=${proxyContext.runtimeClass}, params=${proxyContext.params}, exception=${f.stackTrace}", - clazz, - proxyContext.params, - proxyContext.op, - f, - ) - } - } -} diff --git a/distage/distage-core-proxy-cglib/src/test/scala/izumi/.keep b/distage/distage-core-proxy-cglib/src/test/scala/izumi/.keep deleted file mode 100644 index e69de29bb2..0000000000