diff --git a/macros/src/main/scala/org/zalando/grafter/macros/ReaderMacro.scala b/macros/src/main/scala/org/zalando/grafter/macros/ReaderMacro.scala index 179181d..bb61d7a 100644 --- a/macros/src/main/scala/org/zalando/grafter/macros/ReaderMacro.scala +++ b/macros/src/main/scala/org/zalando/grafter/macros/ReaderMacro.scala @@ -49,11 +49,11 @@ object ReaderMacro { // if there are no case class parameters we need to create a fake // "unit" parameter to avoid clashes with the "transitiveReader" implicit created by the @readers - // annotation. In return the @returns annotation provides an implicit Reader[A, Unit] + // annotation. In return the @readers annotation provides an implicit Reader[A, Unit] if (caseclassParameters.isEmpty) outputs(c)(classTree, className, companionTree) { q""" - implicit def reader[$genericTypeName, $tp](implicit unitReader: cats.data.Reader[$genericTypeName, Unit], ..$implicitReaderParameters): cats.data.Reader[$genericTypeName, $className[${tp.name}]] = { + implicit def reader[$genericTypeName, $tp](implicit unitReader: cats.data.Reader[$genericTypeName, org.zalando.grafter.macros.GrafterUnit], ..$implicitReaderParameters): cats.data.Reader[$genericTypeName, $className[${tp.name}]] = { cats.data.Reader { r => // to avoid unused value warning if (true) unitReader else unitReader @@ -75,6 +75,20 @@ object ReaderMacro { } case Nil => + if (caseclassParameters.isEmpty) + outputs(c)(classTree, className, companionTree) { + q""" + + implicit def reader[$genericTypeName](implicit unitReader: cats.data.Reader[$genericTypeName, org.zalando.grafter.macros.GrafterUnit], ..$implicitReaderParameters): cats.data.Reader[$genericTypeName, $className] = { + cats.data.Reader { r => + // to avoid unused value warning + if (true) unitReader else unitReader + new ${TypeName(klassName)} + } + } + """ + } + else outputs(c)(classTree, className, companionTree) { q""" implicit def reader[$genericTypeName](implicit ..$readerImplicitParameters): cats.data.Reader[$genericTypeName, $className] = { @@ -99,6 +113,14 @@ object ReaderMacro { } +case class GrafterUnit() + +object GrafterUnit { + implicit def unitReader[A]: cats.data.Reader[A, org.zalando.grafter.macros.GrafterUnit] = + cats.data.Reader(_ => org.zalando.grafter.macros.GrafterUnit()) + +} + class reader extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro ReaderMacro.impl } diff --git a/macros/src/main/scala/org/zalando/grafter/macros/ReadersMacro.scala b/macros/src/main/scala/org/zalando/grafter/macros/ReadersMacro.scala index 96864ec..f191cec 100644 --- a/macros/src/main/scala/org/zalando/grafter/macros/ReadersMacro.scala +++ b/macros/src/main/scala/org/zalando/grafter/macros/ReadersMacro.scala @@ -59,10 +59,6 @@ object ReadersMacro { q""" ..$implicitReaders ..$implicitTransitiveReaders - - implicit def unitReader: cats.data.Reader[$className, Unit] = - cats.data.Reader(_ => ()) - ..$readerIdentity """ } diff --git a/tests/src/test/scala/org/zalando/grafter/ParameterlessComponentSpec.scala b/tests/src/test/scala/org/zalando/grafter/ParameterlessComponentSpec.scala new file mode 100644 index 0000000..80d9849 --- /dev/null +++ b/tests/src/test/scala/org/zalando/grafter/ParameterlessComponentSpec.scala @@ -0,0 +1,48 @@ +package org.zalando.grafter.macros + + +/** + * This is a compilation test to check that a component without parameters + * can still be injected. see #124 + */ +object ParameterlessComponentSpec { + @readers + case class ApplicationConfiguration(httpConfig: HttpConfig, additionalConfig: AdditionalConfig) + + /** + * For a nested configuration you need to annotate the nested elements with the @readers annotation + * as well + */ + @readers + case class HttpConfig(cfg1: HttpSubConfig1, cfg2: HttpSubConfig2) + + case class HttpSubConfig1(port: Int) + case class HttpSubConfig2(host: String) + case class AdditionalConfig(config3: String) + + @reader + case class HttpClient(config: HttpSubConfig2) + + + @reader + case class SomeService(client: HttpClient) + + @reader + case class SomeServiceWithoutParameters() + + @reader + case class WebApplication(someService: SomeService, emptyService: SomeServiceWithoutParameters) + + + object MyApp extends App { + + val config = ApplicationConfiguration( + HttpConfig(HttpSubConfig1(80), HttpSubConfig2("bla")), + AdditionalConfig("3") + ) + + val app = WebApplication.reader[ApplicationConfiguration].apply(config) + + } +} +