Repository: 7mind/izumi
Pull request #1223 (2020-09-16 14:43:04)

Use axis defaults from #1030 in `BootstrapLocator`


Patch:
diff --git a/build.sbt b/build.sbt
index 87e6e100a..8ecddfec6 100644
--- a/build.sbt
+++ b/build.sbt
@@ -363,6 +363,26 @@ lazy val `fundamentals-reflection` = project.in(file("fundamentals/fundamentals-
     unmanagedResourceDirectories in Compile += baseDirectory.value / ".jvm/src/main/resources" ,
     unmanagedSourceDirectories in Test += baseDirectory.value / ".jvm/src/test/scala" ,
     unmanagedResourceDirectories in Test += baseDirectory.value / ".jvm/src/test/resources" ,
+    unmanagedSourceDirectories in Compile ++= (unmanagedSourceDirectories in Compile).value.flatMap {
+      dir =>
+       val partialVersion = CrossVersion.partialVersion(scalaVersion.value)
+       def scalaDir(s: String) = file(dir.getPath + s)
+       (partialVersion match {
+         case Some((2, n)) => Seq(scalaDir("_2"), scalaDir("_2." + n.toString))
+         case Some((x, n)) => Seq(scalaDir("_3"), scalaDir("_" + x.toString + "." + n.toString))
+         case None         => Seq.empty
+       })
+    },
+    unmanagedSourceDirectories in Test ++= (unmanagedSourceDirectories in Test).value.flatMap {
+      dir =>
+       val partialVersion = CrossVersion.partialVersion(scalaVersion.value)
+       def scalaDir(s: String) = file(dir.getPath + s)
+       (partialVersion match {
+         case Some((2, n)) => Seq(scalaDir("_2"), scalaDir("_2." + n.toString))
+         case Some((x, n)) => Seq(scalaDir("_3"), scalaDir("_" + x.toString + "." + n.toString))
+         case None         => Seq.empty
+       })
+    },
     scalacOptions ++= Seq(
       s"-Xmacro-settings:scala-version=${scalaVersion.value}",
       s"-Xmacro-settings:scala-versions=${crossScalaVersions.value.mkString(":")}"
@@ -967,7 +987,8 @@ lazy val `distage-core` = project.in(file("distage/distage-core"))
       "org.typelevel" %% "cats-core" % V.cats % Test,
       "org.typelevel" %% "cats-effect" % V.cats_effect % Test,
       "dev.zio" %% "zio" % V.zio % Test,
-      "io.monix" %% "monix-bio" % V.monix_bio % Test
+      "io.monix" %% "monix-bio" % V.monix_bio % Test,
+      "javax.inject" % "javax.inject" % "1" % Test
     )
   )
   .settings(
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala
index 38dda708e..e636d9da6 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala
@@ -8,8 +8,6 @@ import izumi.distage.model.reflection._
 import izumi.fundamentals.platform.language.SourceFilePosition
 import izumi.reflect.Tag
 
-import scala.language.reflectiveCalls
-
 sealed trait Binding {
   def key: DIKey
   def origin: SourceFilePosition
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
index ea8ebd402..e761f4368 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
@@ -1,7 +1,6 @@
 package izumi.distage.model.definition
 
 import izumi.distage.AbstractLocator
-import izumi.distage.model.{Locator, LocatorMeta}
 import izumi.distage.model.definition.Binding.{EmptySetBinding, SetElementBinding, SingletonBinding}
 import izumi.distage.model.definition.ImplDef.InstanceImpl
 import izumi.distage.model.definition.dsl.AbstractBindingDefDSL
@@ -19,6 +18,7 @@ import izumi.distage.model.plan.topology.PlanTopology.PlanTopologyImmutable
 import izumi.distage.model.provisioning.PlanInterpreter
 import izumi.distage.model.references.IdentifiedRef
 import izumi.distage.model.reflection._
+import izumi.distage.model.{Locator, LocatorMeta}
 import izumi.fundamentals.platform.language.{CodePositionMaterializer, SourceFilePosition}
 import izumi.reflect.{Tag, TagK}
 
@@ -66,7 +66,7 @@ trait LocatorDef extends AbstractLocator with AbstractBindingDefDSL[LocatorDef.B
         map += (key -> instance)
       case SetElementBinding(key, InstanceImpl(_, instance), _, _) =>
         val setKey = key.set
-        map += (setKey -> (map.getOrElse(setKey, Set.empty[Any]).asInstanceOf[collection.Set[Any]] + instance))
+        map += (setKey -> (map.getOrElse(setKey, Set.empty[Any]).asInstanceOf[Set[Any]] + instance))
       case e: EmptySetBinding[_] =>
         map.getOrElseUpdate(e.key, Set.empty[Any])
       case b =>
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/StandardAxis.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/StandardAxis.scala
index 363bc9104..d672b87b7 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/StandardAxis.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/StandardAxis.scala
@@ -14,7 +14,7 @@ object StandardAxis {
 
   /**
     * Any entities which may store and persist state or "repositories".
-    * E.g. databases, message queues, KV storages, file systems, etc.
+    * e.g. databases, message queues, KV storages, file systems, etc.
     */
   object Repo extends Axis {
     override def name: String = "repo"
@@ -25,16 +25,16 @@ object StandardAxis {
 
   /**
     * Third-party integrations which are not controlled by the application and provided "as is".
-    * E.g. Facebook API, Google API, etc.
+    * e.g. Facebook API, Google API, etc.
     */
   object World extends Axis {
     override def name: String = "world"
 
     case object Real extends AxisValueDef
-    case object Dummy extends AxisValueDef
+    case object Mock extends AxisValueDef
   }
 
-  @deprecated("Use StandardAxis.Externals instead", "0.11.0")
+  @deprecated("Use StandardAxis.World instead", "0.11.0")
   final val ExternalApi = World
 
   /**
@@ -75,7 +75,7 @@ object StandardAxis {
     Activation(
       Mode -> Mode.Test,
       Repo -> Repo.Dummy,
-      World -> World.Dummy,
+      World -> World.Mock,
       Scene -> Scene.Managed,
     )
   }
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 196a70eaa..81b963377 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
@@ -155,12 +155,10 @@ object BootstrapLocator {
     make[BindingTranslator].from[BindingTranslator.Impl]
 
     make[ProxyProvider].tagged(Cycles.Proxy).from[CglibProxyProvider]
-    make[ProxyProvider].tagged(Cycles.Byname).from[ProxyProviderFailingImpl]
-    make[ProxyProvider].tagged(Cycles.Disable).from[ProxyProviderFailingImpl]
+    make[ProxyProvider].from[ProxyProviderFailingImpl]
 
-    make[ProxyStrategy].tagged(Cycles.Proxy).from[ProxyStrategyDefaultImpl]
-    make[ProxyStrategy].tagged(Cycles.Byname).from[ProxyStrategyDefaultImpl]
     make[ProxyStrategy].tagged(Cycles.Disable).from[ProxyStrategyFailingImpl]
+    make[ProxyStrategy].from[ProxyStrategyDefaultImpl]
   }
 
   final val defaultBootstrapActivation: Activation = Activation(Cycles -> Cycles.Proxy)
diff --git a/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapPlanningObserver.scala b/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapPlanningObserver.scala
index 3544748e6..b6b9246eb 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapPlanningObserver.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapPlanningObserver.scala
@@ -1,6 +1,6 @@
 package izumi.distage.bootstrap
 
-import izumi.distage.model.plan.{OrderedPlan, SemiPlan}
+import izumi.distage.model.plan.OrderedPlan
 import izumi.distage.model.planning.PlanningObserver
 import izumi.fundamentals.platform.console.TrivialLogger
 
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala
index 9fcb8ffab..93d722f03 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala
@@ -2,15 +2,12 @@ package izumi.distage.planning
 
 import izumi.distage.model.definition.Binding.{EmptySetBinding, ImplBinding, SetElementBinding}
 import izumi.distage.model.definition.{Binding, ImplDef, ModuleBase}
-import izumi.distage.model.plan.{ExecutableOp, OrderedPlan}
 import izumi.distage.model.planning.PlanningHook
 import izumi.distage.model.reflection.DIKey.SetElementKey
 import izumi.distage.model.reflection._
 import izumi.fundamentals.platform.language.CodePositionMaterializer
 import izumi.reflect.Tag
 
-import scala.collection.immutable.ListSet
-
 /**
   * A hook that will collect all implementations with types that are {{{_ <: T}}} into a `Set[T]` set binding
   * available for summoning
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
index 82c0e57e9..a7b038462 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
@@ -145,7 +145,6 @@ class PlannerDefaultImpl(
     import scala.collection.compat._
 
     val activations: Set[AxisPoint] = input.activation.activeChoices.map { case (a, c) => AxisPoint(a.name, c.id) }.toSet
-    val activationChoices = ActivationChoices(activations)
 
     val allOps: Vector[(Annotated[DIKey], InstantiationOp)] = input
       .bindings.bindings.iterator
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpBootstrapModule.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpBootstrapModule.scala
index a51156504..88d5e7ca1 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpBootstrapModule.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpBootstrapModule.scala
@@ -4,6 +4,8 @@ import izumi.distage.model.definition.BootstrapModuleDef
 import izumi.distage.model.planning.PlanningObserver
 
 class GraphDumpBootstrapModule extends BootstrapModuleDef {
+  // GraphDumpObserver doesn't work on sjs
+
   many[PlanningObserver]
     .add[GraphDumpObserver]
 }
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala
index be155853c..7d8437ecc 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala
@@ -5,10 +5,10 @@ import izumi.distage.model.plan.ExecutableOp.CreateSet
 import izumi.distage.model.provisioning.strategies.SetStrategy
 import izumi.distage.model.provisioning.{NewObjectOp, ProvisioningKeyProvider, WiringExecutor}
 import izumi.distage.model.reflection._
-import izumi.fundamentals.platform.language.unused
 import izumi.fundamentals.collections.OrderedSetShim
+import izumi.fundamentals.platform.language.unused
 
-import scala.collection.{Iterable, mutable}
+import scala.collection.Iterable
 
 class SetStrategyDefaultImpl extends SetStrategy {
   def makeSet(context: ProvisioningKeyProvider, @unused executor: WiringExecutor, op: CreateSet): Seq[NewObjectOp.NewInstance] = {
diff --git a/fundamentals/fundamentals-language/src/main/scala/izumi/fundamentals/platform/language/IzScala.scala b/fundamentals/fundamentals-language/src/main/scala/izumi/fundamentals/platform/language/IzScala.scala
index 11c590662..45fe3ff83 100644
--- a/fundamentals/fundamentals-language/src/main/scala/izumi/fundamentals/platform/language/IzScala.scala
+++ b/fundamentals/fundamentals-language/src/main/scala/izumi/fundamentals/platform/language/IzScala.scala
@@ -1,6 +1,8 @@
 package izumi.fundamentals.platform.language
 
+import scala.language.experimental.macros
 import scala.math.Ordering.Implicits._
+import scala.reflect.macros.blackbox
 
 object IzScala {
 
@@ -40,5 +42,25 @@ object IzScala {
     }
   }
 
-  def scalaRelease: ScalaRelease = ScalaRelease.parse(scala.util.Properties.versionNumberString)
+  def scalaRelease: IzScala.ScalaRelease = macro ScalaReleaseMacro.scalaRelease
+
+  object ScalaReleaseMacro {
+
+    def scalaRelease(c: blackbox.Context): c.Expr[IzScala.ScalaRelease] = {
+      import c.universe._
+
+      ScalaRelease.parse(scala.util.Properties.versionNumberString) match {
+        case ScalaRelease.`2_12`(bugfix) =>
+          c.Expr[ScalaRelease](q"${symbolOf[ScalaRelease.`2_12`].asClass.companion}($bugfix)")
+        case ScalaRelease.`2_13`(bugfix) =>
+          c.Expr[ScalaRelease](q"${symbolOf[ScalaRelease.`2_13`].asClass.companion}($bugfix)")
+        case ScalaRelease.Unsupported(parts) =>
+          c.Expr[ScalaRelease](q"${symbolOf[ScalaRelease.Unsupported].asClass.companion}(..${parts.toList})")
+        case ScalaRelease.Unknown(verString) =>
+          c.Expr[ScalaRelease](q"${symbolOf[ScalaRelease.Unknown].asClass.companion}($verString)")
+      }
+    }
+
+  }
+
 }
diff --git a/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/AnnotationTools.scala b/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/AnnotationTools.scala
index 23fa391ef..5805d128b 100644
--- a/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/AnnotationTools.scala
+++ b/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/AnnotationTools.scala
@@ -7,7 +7,8 @@ import scala.reflect.api.Universe
 object AnnotationTools {
 
   def getAllAnnotations(u: Universe)(symb: u.Symbol): List[u.Annotation] = {
-    symb.annotations ++ getAllTypeAnnotations(u)(symb.typeSignature)
+    val out = symb.annotations ++ getAllTypeAnnotations(u)(symb.typeSignature)
+    out
   }
 
   def getAllTypeAnnotations(u: Universe)(typ: u.Type): List[u.Annotation] = {
diff --git a/fundamentals/fundamentals-reflection/src/main/scala_2.12/izumi/fundamentals/reflection/JSRAnnotationTools.scala b/fundamentals/fundamentals-reflection/src/main/scala_2.12/izumi/fundamentals/reflection/JSRAnnotationTools.scala
index 83e398fa6..85f5d451f 100644
--- a/fundamentals/fundamentals-reflection/src/main/scala_2.12/izumi/fundamentals/reflection/JSRAnnotationTools.scala
+++ b/fundamentals/fundamentals-reflection/src/main/scala_2.12/izumi/fundamentals/reflection/JSRAnnotationTools.scala
@@ -19,20 +19,19 @@ object JSRAnnotationTools {
       .collect {
         case a: u.AnnotationApi =>
           a.tree.children match {
-//            case (select: u.Select) :: (value: u.NamedArg) :: Nil =>
-//              (select.children.headOption, value.lhs, value.rhs) match {
-//                case (Some(n: u.NewApi), i: u.IdentApi, v: u.LiteralApi) if v.value.value.isInstanceOf[String] && i.name.toString == "value" =>
-//                  n.children match {
-//                    case (head: u.TypeTreeApi) :: Nil if head.symbol.name.toString == "Named" =>
-//                      Some(v.value.value.asInstanceOf[String])
-//                    case _ =>
-//                      None
-//                  }
-//
-//                case _ =>
-//                  None
-//              }
+            case (select: u.Select) :: (value: u.AssignOrNamedArgApi) :: Nil =>
+              (select.children.headOption, value.lhs, value.rhs) match {
+                case (Some(n: u.NewApi), i: u.IdentApi, v: u.LiteralApi) if v.value.value.isInstanceOf[String] && i.name.toString == "value" =>
+                  n.children match {
+                    case (head: u.TypeTreeApi) :: Nil if head.symbol.name.toString == "Named" =>
+                      Some(v.value.value.asInstanceOf[String])
+                    case _ =>
+                      None
+                  }
 
+                case _ =>
+                  None
+              }
             case _ =>
               Option.empty[String]
           }
diff --git a/fundamentals/fundamentals-reflection/src/main/scala_2.13/izumi/fundamentals/reflection/JSRAnnotationTools.scala b/fundamentals/fundamentals-reflection/src/main/scala_2.13/izumi/fundamentals/reflection/JSRAnnotationTools.scala
index 551fb9ccd..b96daa414 100644
--- a/fundamentals/fundamentals-reflection/src/main/scala_2.13/izumi/fundamentals/reflection/JSRAnnotationTools.scala
+++ b/fundamentals/fundamentals-reflection/src/main/scala_2.13/izumi/fundamentals/reflection/JSRAnnotationTools.scala
@@ -19,7 +19,7 @@ object JSRAnnotationTools {
       .collect {
         case a: u.AnnotationApi =>
           a.tree.children match {
-            case (select: u.Select) :: (value: u.NamedArg) :: Nil =>
+            case (select: u.SelectApi) :: (value: u.NamedArgApi) :: Nil =>
               (select.children.headOption, value.lhs, value.rhs) match {
                 case (Some(n: u.NewApi), i: u.IdentApi, v: u.LiteralApi) if v.value.value.isInstanceOf[String] && i.name.toString == "value" =>
                   n.children match {


Test patch:
diff --git a/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/JSRAnnotationTest.scala b/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/JSRAnnotationTest.scala
deleted file mode 100644
index 2593b08a4..000000000
--- a/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/JSRAnnotationTest.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-package izumi.distage.injector
-
-import distage.{Id, Injector, ModuleDef}
-import izumi.distage.gc.MkGcInjector
-import izumi.distage.model.PlannerInput
-import izumi.fundamentals.platform.language.IzScala
-import izumi.fundamentals.platform.language.IzScala.ScalaRelease
-import org.scalatest.wordspec.AnyWordSpec
-
-class JSRAnnotationTest extends AnyWordSpec with MkGcInjector {
-  import JSRAnnotationTest._
-  "distage" should {
-    "support JSR330 @Named anno" in {
-      IzScala.scalaRelease match {
-        case ScalaRelease.`2_13`(bugfix) =>
-          val definition = PlannerInput.noGC(new ModuleDef {
-            make[Int].named("port").from(80)
-            make[String].named("address").from("localhost")
-            make[ServerConfig].from(ServerConfig)
-          })
-
-          val context = Injector.Standard().produce(definition).unsafeGet()
-
-          assert(context.get[ServerConfig].port == context.get[Int]("port"))
-          assert(context.get[ServerConfig].address == context.get[String]("address"))
-        case _ =>
-      }
-
-    }
-  }
-}
-
-object JSRAnnotationTest {
-  type Port = Int @javax.inject.Named(value = "port")
-  type Address = String @Id("address")
-
-  final case class ServerConfig(port: Port, address: Address)
-}
diff --git a/distage/distage-core/src/test/scala/izumi/distage/compat/CatsResourcesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/compat/CatsResourcesTest.scala
index 3ef546e31..27dac1b37 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/compat/CatsResourcesTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/compat/CatsResourcesTest.scala
@@ -112,7 +112,7 @@ final class CatsResourcesTest extends AnyWordSpec with GivenWhenThen {
     assertCompiles(
       """
          new ModuleDef {
-           make[String].fromResource { (_: Unit) => Resource.pure("42") }
+           make[String].fromResource { (_: Unit) => Resource.pure[cats.Id, String]("42") }
          }
       """
     )
@@ -120,7 +120,7 @@ final class CatsResourcesTest extends AnyWordSpec with GivenWhenThen {
       assertCompiles(
         """
          new ModuleDef {
-           make[String].fromResource { (_: Unit) => Resource.pure(42) }
+           make[String].fromResource { (_: Unit) => Resource.pure[cats.Id, Int](42) }
          }
       """
       )
diff --git a/distage/distage-core/src/test/scala/izumi/distage/fixtures/ProviderCases.scala b/distage/distage-core/src/test/scala/izumi/distage/fixtures/ProviderCases.scala
index 0bb108492..0a2c8f3ae 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/fixtures/ProviderCases.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/fixtures/ProviderCases.scala
@@ -34,6 +34,7 @@ object ProviderCases {
 
     case class ClassArgAnn(@Id("classargann1") x: String, @Id("classargann2") y: Int)
     case class ClassTypeAnn(x: String @Id("classtypeann1"), y: Int @Id("classtypeann2"))
+    case class ClassTypeAnnJavax(x: String @javax.inject.Named("classtypeann1"), y: Int @javax.inject.Named("classtypeann2"))
     class ClassTypeAnnByName(@unused x: => String @Id("classtypeann1"), @unused y: => Int @Id("classtypeann2"))
 
     class Poly[F[_]]
diff --git a/distage/distage-core/src/test/scala/izumi/distage/impl/FunctoidTest.scala b/distage/distage-core/src/test/scala/izumi/distage/impl/FunctoidTest.scala
index 7fc54457c..7dd47acb8 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/impl/FunctoidTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/impl/FunctoidTest.scala
@@ -230,6 +230,13 @@ class FunctoidTest extends AnyWordSpec {
       assert(fn.diKeys contains DIKey.get[Int].named("classtypeann2"))
     }
 
+    "handle case class .apply references with javax.inject.Named annotations" in {
+      val fn = Functoid.apply(ClassTypeAnnJavax.apply _).get
+
+      assert(fn.diKeys contains DIKey.get[String].named("classtypeann1"))
+      assert(fn.diKeys contains DIKey.get[Int].named("classtypeann2"))
+    }
+
     "handle generic case class .apply references with type annotations" in {
       val fn = Functoid.apply(ClassTypeAnnT.apply[String, Int] _).get
 
diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/JSRAnnotationTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/JSRAnnotationTest.scala
new file mode 100644
index 000000000..84ca24d06
--- /dev/null
+++ b/distage/distage-core/src/test/scala/izumi/distage/injector/JSRAnnotationTest.scala
@@ -0,0 +1,122 @@
+package izumi.distage.injector
+
+import distage.{Id, Injector, ModuleDef}
+import izumi.distage.gc.MkGcInjector
+import izumi.distage.model.PlannerInput
+import izumi.distage.model.exceptions.ProvisioningException
+import org.scalatest.wordspec.AnyWordSpec
+
+class JSRAnnotationTest extends AnyWordSpec with MkGcInjector {
+  import JSRAnnotationTest._
+  "JSR330 @Named anno" should {
+    "work when no functoid is involved" in {
+      val definition = PlannerInput.noGC(new ModuleDef {
+        make[Int].named("port").from(80)
+        make[String].named("address").from("localhost")
+        make[Int].named("port1").from(90)
+        make[String].named("address1").from("localhost1")
+        make[ServerConfig]
+      })
+
+      val context = Injector.Standard().produce(definition).unsafeGet()
+
+      assert(context.get[ServerConfig].port == context.get[Int]("port"))
+      assert(context.get[ServerConfig].port1 == context.get[Int]("port1"))
+
+      assert(context.get[ServerConfig].address == context.get[String]("address"))
+      assert(context.get[ServerConfig].address1 == context.get[String]("address1"))
+    }
+
+    "progression: work with combined annos when functoid takes companion as function" in
+    intercept[ProvisioningException] {
+      val definition = PlannerInput.noGC(new ModuleDef {
+        make[Int].named("port").from(80)
+        make[String].named("address").from("localhost")
+        make[Int].named("port1").from(90)
+        make[String].named("address1").from("localhost1")
+        make[ServerConfig].from(ServerConfig.apply _)
+      })
+
+      val context = Injector.Standard().produce(definition).unsafeGet()
+
+      assert(context.get[ServerConfig].port == context.get[Int]("port"))
+      assert(context.get[ServerConfig].port1 == context.get[Int]("port1"))
+
+      assert(context.get[ServerConfig].address == context.get[String]("address"))
+      assert(context.get[ServerConfig].address1 == context.get[String]("address1"))
+    }
+
+    "work with field annos when functoid takes .apply" in {
+      val definition = PlannerInput.noGC(new ModuleDef {
+        make[Int].named("port1").from(90)
+        make[String].named("address1").from("localhost1")
+        make[ServerConfigWithFieldAnnos].from(ServerConfigWithFieldAnnos.apply _)
+      })
+
+      val context = Injector.Standard().produce(definition).unsafeGet()
+
+      assert(context.get[ServerConfigWithFieldAnnos].port1 == context.get[Int]("port1"))
+      assert(context.get[ServerConfigWithFieldAnnos].address1 == context.get[String]("address1"))
+    }
+
+    "work with alias annos when functoid takes .apply" in {
+      val definition = PlannerInput.noGC(new ModuleDef {
+        make[Int].named("port").from(80)
+        make[String].named("address").from("localhost")
+        make[ServerConfigWithTypeAnnos].from(ServerConfigWithTypeAnnos.apply _)
+      })
+
+      val context = Injector.Standard().produce(definition).unsafeGet()
+      assert(context.get[ServerConfigWithTypeAnnos].port == context.get[Int]("port"))
+      assert(context.get[ServerConfigWithTypeAnnos].address == context.get[String]("address"))
+    }
+
+    "work with field annos when functoid takes companion as function" in
+    intercept[ProvisioningException] {
+      val definition = PlannerInput.noGC(new ModuleDef {
+        make[Int].named("port1").from(90)
+        make[String].named("address1").from("localhost1")
+        make[ServerConfigWithFieldAnnos].from(ServerConfigWithFieldAnnos)
+      })
+
+      val context = Injector.Standard().produce(definition).unsafeGet()
+
+      assert(context.get[ServerConfigWithFieldAnnos].port1 == context.get[Int]("port1"))
+      assert(context.get[ServerConfigWithFieldAnnos].address1 == context.get[String]("address1"))
+    }
+
+    "work with alias annos when functoid takes companion as function" in {
+      val definition = PlannerInput.noGC(new ModuleDef {
+        make[Int].named("port").from(80)
+        make[String].named("address").from("localhost")
+        make[ServerConfigWithTypeAnnos].from(ServerConfigWithTypeAnnos)
+      })
+
+      val context = Injector.Standard().produce(definition).unsafeGet()
+      assert(context.get[ServerConfigWithTypeAnnos].port == context.get[Int]("port"))
+      assert(context.get[ServerConfigWithTypeAnnos].address == context.get[String]("address"))
+    }
+  }
+}
+
+object JSRAnnotationTest {
+  type Port = Int @javax.inject.Named(value = "port")
+  type Address = String @javax.inject.Named("address")
+
+  final case class ServerConfig(
+    port: Port,
+    address: Address,
+    port1: Int @javax.inject.Named(value = "port1"),
+    address1: String @javax.inject.Named("address1"),
+  )
+
+  final case class ServerConfigWithFieldAnnos(
+    port1: Int @javax.inject.Named(value = "port1"),
+    address1: String @javax.inject.Named("address1"),
+  )
+
+  final case class ServerConfigWithTypeAnnos(
+    port: Port,
+    address: Address,
+  )
+}