How do I inject dependencies into Enums

Question from Chem#9771

In javax, if you use @Inject into a constructor, but you have instances where you can't pass those parameters, what do you do?

@ApplicationScoped
public class JavascriptLanguageExecutor extends LanguageExecutor {
   @Inject
   JavascriptLanguageExecutor(EngineInstance engine) {
       super(Language.JAVASCRIPT, engine.instance);
   }
}

public enum Language {
   JAVASCRIPT("js");

   public LanguageExecutor getExecutor() {
       return switch (this) {
           // THIS NEEDS "EngineInstance" BUT I DON'T HAVE ABILITY TO "@Inject" INTO ENUMS
           case JAVASCRIPT -> new JavascriptLanguageExecutor();
       };
   }

So here this EngineInstance is available via injection in the app but you can't use this inside of enums I think, and so I can't actually instantiate the class there.

Could I move it out of the constructor and do a field injection

In that case, you need to pass an EngineInstance.

Sounds dumb, but yeah. Ignore all the javax requirements for a second, since they aren't super relevant.

public class JavascriptLanguageExecutor extends LanguageExecutor {
    JavascriptLanguageExecutor(EngineInstance engine) {
        super(Language.JAVASCRIPT, engine.instance);
    }
}

What you want is, effectively, a map of Language -> Executor. So just make one.

var executors = new EnumMap<Language, LanguageExecutor>(...);

And then pass it around where you need it.

There are more options but generally speaking Java is structured in a way where passing the thing is the path of least resistance. Unless you made your LanguageExecutors work with the service provider stuff, but that's somewhat niche (for application code).

Im not gonna pretend you can't also have a static map and fill it up with instances - you can. Just then you need to be careful of when it is hydrated vs. uninitialized and make sure to synchronize if you need to etc.


<- Index