Can I use Dagger 2's field injection in Kotlin?











up vote
12
down vote

favorite












I posted a question (Dagger 2 does not generate the component class (Android, Kotlin)), and after some experiments, it seems that the problem might be due to that Kotlin hides the field.



class CoffeeShop {
@Inject
var theCoffee: Coffee? = null
}


The error message is,



:app:kaptDebugKotline: ...CoffeeShop.java:7:
error: Dagger does not support injection into private fields
e: private ....Coffee theCoffee;


theCoffee was not private in my source code. But I think Kotlin may be translating



class CoffeeShop {
@Inject
var theCoffee: Coffee? = null
}


into Java code of



class CoffeeShop {
@Inject
private Coffee theCoffee = null;
public Coffee getTheCoffee();
public void setTheCoffee();
}


Can I use field injection in Kotlin?










share|improve this question




























    up vote
    12
    down vote

    favorite












    I posted a question (Dagger 2 does not generate the component class (Android, Kotlin)), and after some experiments, it seems that the problem might be due to that Kotlin hides the field.



    class CoffeeShop {
    @Inject
    var theCoffee: Coffee? = null
    }


    The error message is,



    :app:kaptDebugKotline: ...CoffeeShop.java:7:
    error: Dagger does not support injection into private fields
    e: private ....Coffee theCoffee;


    theCoffee was not private in my source code. But I think Kotlin may be translating



    class CoffeeShop {
    @Inject
    var theCoffee: Coffee? = null
    }


    into Java code of



    class CoffeeShop {
    @Inject
    private Coffee theCoffee = null;
    public Coffee getTheCoffee();
    public void setTheCoffee();
    }


    Can I use field injection in Kotlin?










    share|improve this question


























      up vote
      12
      down vote

      favorite









      up vote
      12
      down vote

      favorite











      I posted a question (Dagger 2 does not generate the component class (Android, Kotlin)), and after some experiments, it seems that the problem might be due to that Kotlin hides the field.



      class CoffeeShop {
      @Inject
      var theCoffee: Coffee? = null
      }


      The error message is,



      :app:kaptDebugKotline: ...CoffeeShop.java:7:
      error: Dagger does not support injection into private fields
      e: private ....Coffee theCoffee;


      theCoffee was not private in my source code. But I think Kotlin may be translating



      class CoffeeShop {
      @Inject
      var theCoffee: Coffee? = null
      }


      into Java code of



      class CoffeeShop {
      @Inject
      private Coffee theCoffee = null;
      public Coffee getTheCoffee();
      public void setTheCoffee();
      }


      Can I use field injection in Kotlin?










      share|improve this question















      I posted a question (Dagger 2 does not generate the component class (Android, Kotlin)), and after some experiments, it seems that the problem might be due to that Kotlin hides the field.



      class CoffeeShop {
      @Inject
      var theCoffee: Coffee? = null
      }


      The error message is,



      :app:kaptDebugKotline: ...CoffeeShop.java:7:
      error: Dagger does not support injection into private fields
      e: private ....Coffee theCoffee;


      theCoffee was not private in my source code. But I think Kotlin may be translating



      class CoffeeShop {
      @Inject
      var theCoffee: Coffee? = null
      }


      into Java code of



      class CoffeeShop {
      @Inject
      private Coffee theCoffee = null;
      public Coffee getTheCoffee();
      public void setTheCoffee();
      }


      Can I use field injection in Kotlin?







      kotlin dagger-2






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 22 at 15:38









      William Reed

      762818




      762818










      asked Nov 12 '17 at 11:53









      Damn Vegetables

      2,27722244




      2,27722244
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          27
          down vote



          accepted











          I think Kotlin may be translating [...] into Java code of [...]




          And you would be correct, that's exactly what happens.



          Typically in Kotlin you wouldn't write



          @Inject var coffee: Coffee? = null


          because when you're going to access coffee, it will never be null. In other words you will always inject the object before accessing it's fields. That makes the operators !! redundant and ? unnecessary. Kotlin has lateinit property modifier to express this.



          @Inject lateinit var coffee: Coffee


          When you use lateinit the generated field has the same visibility as its getter and setter, in this case public. This makes it work with Dagger.



          You can see the result by viewing generated Kotlin bytecode.




          Main menu > Tools > Kotlin > Show Kotlin Bytecode




          However, even better approach would be injecting the class constructor:



          class CoffeeShop @Inject constructor(val coffee: Coffee) {
          //...
          }


          In this case coffee is not var and can't be reassigned.



          Injecting constructor is not an option when the instance is created for you by a framework, Android activity is a good example.





          Note: When using qualifiers you have to specify field annotation target on them:



          @Inject @field:Named("Arabica") @field:Arabica
          lateinit var coffee: Coffee





          Can I use field injection in Kotlin?




          Yes you can. As explained above, field injection is actually applied for lateinit properties.



          But you were probably interested in generating and injecting fields without getter/setter in Kotlin.



          @JvmField @Inject
          var coffee: Coffee? = null





          share|improve this answer























          • Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
            – Damn Vegetables
            Nov 12 '17 at 12:26










          • @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
            – Eugen Pechanec
            Nov 12 '17 at 13:05










          • Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
            – Damn Vegetables
            Nov 12 '17 at 13:36










          • @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
            – Eugen Pechanec
            Nov 12 '17 at 13:47













          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47248478%2fcan-i-use-dagger-2s-field-injection-in-kotlin%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          27
          down vote



          accepted











          I think Kotlin may be translating [...] into Java code of [...]




          And you would be correct, that's exactly what happens.



          Typically in Kotlin you wouldn't write



          @Inject var coffee: Coffee? = null


          because when you're going to access coffee, it will never be null. In other words you will always inject the object before accessing it's fields. That makes the operators !! redundant and ? unnecessary. Kotlin has lateinit property modifier to express this.



          @Inject lateinit var coffee: Coffee


          When you use lateinit the generated field has the same visibility as its getter and setter, in this case public. This makes it work with Dagger.



          You can see the result by viewing generated Kotlin bytecode.




          Main menu > Tools > Kotlin > Show Kotlin Bytecode




          However, even better approach would be injecting the class constructor:



          class CoffeeShop @Inject constructor(val coffee: Coffee) {
          //...
          }


          In this case coffee is not var and can't be reassigned.



          Injecting constructor is not an option when the instance is created for you by a framework, Android activity is a good example.





          Note: When using qualifiers you have to specify field annotation target on them:



          @Inject @field:Named("Arabica") @field:Arabica
          lateinit var coffee: Coffee





          Can I use field injection in Kotlin?




          Yes you can. As explained above, field injection is actually applied for lateinit properties.



          But you were probably interested in generating and injecting fields without getter/setter in Kotlin.



          @JvmField @Inject
          var coffee: Coffee? = null





          share|improve this answer























          • Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
            – Damn Vegetables
            Nov 12 '17 at 12:26










          • @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
            – Eugen Pechanec
            Nov 12 '17 at 13:05










          • Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
            – Damn Vegetables
            Nov 12 '17 at 13:36










          • @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
            – Eugen Pechanec
            Nov 12 '17 at 13:47

















          up vote
          27
          down vote



          accepted











          I think Kotlin may be translating [...] into Java code of [...]




          And you would be correct, that's exactly what happens.



          Typically in Kotlin you wouldn't write



          @Inject var coffee: Coffee? = null


          because when you're going to access coffee, it will never be null. In other words you will always inject the object before accessing it's fields. That makes the operators !! redundant and ? unnecessary. Kotlin has lateinit property modifier to express this.



          @Inject lateinit var coffee: Coffee


          When you use lateinit the generated field has the same visibility as its getter and setter, in this case public. This makes it work with Dagger.



          You can see the result by viewing generated Kotlin bytecode.




          Main menu > Tools > Kotlin > Show Kotlin Bytecode




          However, even better approach would be injecting the class constructor:



          class CoffeeShop @Inject constructor(val coffee: Coffee) {
          //...
          }


          In this case coffee is not var and can't be reassigned.



          Injecting constructor is not an option when the instance is created for you by a framework, Android activity is a good example.





          Note: When using qualifiers you have to specify field annotation target on them:



          @Inject @field:Named("Arabica") @field:Arabica
          lateinit var coffee: Coffee





          Can I use field injection in Kotlin?




          Yes you can. As explained above, field injection is actually applied for lateinit properties.



          But you were probably interested in generating and injecting fields without getter/setter in Kotlin.



          @JvmField @Inject
          var coffee: Coffee? = null





          share|improve this answer























          • Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
            – Damn Vegetables
            Nov 12 '17 at 12:26










          • @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
            – Eugen Pechanec
            Nov 12 '17 at 13:05










          • Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
            – Damn Vegetables
            Nov 12 '17 at 13:36










          • @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
            – Eugen Pechanec
            Nov 12 '17 at 13:47















          up vote
          27
          down vote



          accepted







          up vote
          27
          down vote



          accepted







          I think Kotlin may be translating [...] into Java code of [...]




          And you would be correct, that's exactly what happens.



          Typically in Kotlin you wouldn't write



          @Inject var coffee: Coffee? = null


          because when you're going to access coffee, it will never be null. In other words you will always inject the object before accessing it's fields. That makes the operators !! redundant and ? unnecessary. Kotlin has lateinit property modifier to express this.



          @Inject lateinit var coffee: Coffee


          When you use lateinit the generated field has the same visibility as its getter and setter, in this case public. This makes it work with Dagger.



          You can see the result by viewing generated Kotlin bytecode.




          Main menu > Tools > Kotlin > Show Kotlin Bytecode




          However, even better approach would be injecting the class constructor:



          class CoffeeShop @Inject constructor(val coffee: Coffee) {
          //...
          }


          In this case coffee is not var and can't be reassigned.



          Injecting constructor is not an option when the instance is created for you by a framework, Android activity is a good example.





          Note: When using qualifiers you have to specify field annotation target on them:



          @Inject @field:Named("Arabica") @field:Arabica
          lateinit var coffee: Coffee





          Can I use field injection in Kotlin?




          Yes you can. As explained above, field injection is actually applied for lateinit properties.



          But you were probably interested in generating and injecting fields without getter/setter in Kotlin.



          @JvmField @Inject
          var coffee: Coffee? = null





          share|improve this answer















          I think Kotlin may be translating [...] into Java code of [...]




          And you would be correct, that's exactly what happens.



          Typically in Kotlin you wouldn't write



          @Inject var coffee: Coffee? = null


          because when you're going to access coffee, it will never be null. In other words you will always inject the object before accessing it's fields. That makes the operators !! redundant and ? unnecessary. Kotlin has lateinit property modifier to express this.



          @Inject lateinit var coffee: Coffee


          When you use lateinit the generated field has the same visibility as its getter and setter, in this case public. This makes it work with Dagger.



          You can see the result by viewing generated Kotlin bytecode.




          Main menu > Tools > Kotlin > Show Kotlin Bytecode




          However, even better approach would be injecting the class constructor:



          class CoffeeShop @Inject constructor(val coffee: Coffee) {
          //...
          }


          In this case coffee is not var and can't be reassigned.



          Injecting constructor is not an option when the instance is created for you by a framework, Android activity is a good example.





          Note: When using qualifiers you have to specify field annotation target on them:



          @Inject @field:Named("Arabica") @field:Arabica
          lateinit var coffee: Coffee





          Can I use field injection in Kotlin?




          Yes you can. As explained above, field injection is actually applied for lateinit properties.



          But you were probably interested in generating and injecting fields without getter/setter in Kotlin.



          @JvmField @Inject
          var coffee: Coffee? = null






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 16 at 11:09

























          answered Nov 12 '17 at 12:15









          Eugen Pechanec

          26.1k76889




          26.1k76889












          • Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
            – Damn Vegetables
            Nov 12 '17 at 12:26










          • @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
            – Eugen Pechanec
            Nov 12 '17 at 13:05










          • Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
            – Damn Vegetables
            Nov 12 '17 at 13:36










          • @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
            – Eugen Pechanec
            Nov 12 '17 at 13:47




















          • Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
            – Damn Vegetables
            Nov 12 '17 at 12:26










          • @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
            – Eugen Pechanec
            Nov 12 '17 at 13:05










          • Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
            – Damn Vegetables
            Nov 12 '17 at 13:36










          • @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
            – Eugen Pechanec
            Nov 12 '17 at 13:47


















          Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
          – Damn Vegetables
          Nov 12 '17 at 12:26




          Actually I saw lateinit before posting this question, but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection, is that correct? The error message was Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.. So, doesn't that make the answer to my question a "no"?
          – Damn Vegetables
          Nov 12 '17 at 12:26












          @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
          – Eugen Pechanec
          Nov 12 '17 at 13:05




          @DamnVegetables Damn, I completely missed the question :D Check out the updated answer. but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection Now I'm not sure what you mean by field injection. Calling MembersInjector manually? That works with lateinit. lateinit=field as far as dagger is concerned.
          – Eugen Pechanec
          Nov 12 '17 at 13:05












          Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
          – Damn Vegetables
          Nov 12 '17 at 13:36




          Thank you. If you do not mind, where does Arabica came from? And the error message, @Provides- or @Produces-annotated method, does that mean a provide/produces for CoffeeShop? Because a provide method for Coffee already exists. (The full source is in the question I mentioned.)
          – Damn Vegetables
          Nov 12 '17 at 13:36












          @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
          – Eugen Pechanec
          Nov 12 '17 at 13:47






          @DamnVegetables Arabica is a made up custom qualifier. You probably won't need qualifiers just now. Focus on getting it to work. About the error: Dagger needs to inject val coffee: Coffee and for that it needs to know where Coffee comes from. As the error hints there are two ways. The user guide explains it best, I think.
          – Eugen Pechanec
          Nov 12 '17 at 13:47




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47248478%2fcan-i-use-dagger-2s-field-injection-in-kotlin%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          What visual should I use to simply compare current year value vs last year in Power BI desktop

          Alexandru Averescu

          Trompette piccolo