2

I am trying to use spring injection to inject into an enum. Like this:

public enum Car {
HONDA("Honda", "hondas") {
    @Inject
    Carparts carparts;

    @Override
    public List<Carpart> getCarparts() {
        return carparts.getCarpartsListings();
    }
};
//more logic here
}

My Carparts bean is defined as follows in the configuration class:

@Bean
@Singleton
public Carparts geCarparts() {
    return new Carparts();
}

But no matter what I get a null value for carparts injection. Any help will be greatly appreciated.

ASR4
  • 545
  • 1
  • 8
  • 24
  • I'm not sure if this works at all but *if* that works, then you'll have to make this enum at least a component s.t. it gets picked up by spring. This is not particularly a qualified answer but you need at least something like a [`@Component` annotation](https://stackoverflow.com/a/6897038/826983) on a class that you want to inject into. – Stefan Falk May 23 '18 at 23:43
  • @StefanFalk isn't annotating a class with "Component" another way of making that class a bean? I did not know that a class needs to be annotated with "Component" even for injection. – ASR4 May 23 '18 at 23:47
  • 2
    `@Component` tells Spring that this class should be managed by Spring. [See this answer](https://stackoverflow.com/questions/6827752/whats-the-difference-between-component-repository-service-annotations-in/6897038#6897038) for more details but the essence is that Spring won't inject anything if you don't tell Spring to take care about a class. – Stefan Falk May 23 '18 at 23:49
  • Also [take a look at this](https://stackoverflow.com/a/10604537/826983). – Stefan Falk May 23 '18 at 23:52
  • Still null, but when I have Carparts carparts = new Carparts(); it works fine. – ASR4 May 23 '18 at 23:53
  • Have you tried `@Autowired` instead of `@Inject`? Shouldn't make a difference but you can try. To be honest I have no idea if this will actually work on `enum` types at all. You'll have to wait for somebody who can answer that in more detail I'm afraid. – Stefan Falk May 23 '18 at 23:55
  • I think it's not possible and [this thread](http://forum.spring.io/forum/spring-projects/container/85134-inject-a-dependency-into-an-enum) seems to confirm that. You'll have to consider a workaround I guess. – Stefan Falk May 23 '18 at 23:56
  • 2
    What do you want to achieve? Tell your ultimate goal and we might help by provide a workaround. You cannot inject into an enum because enum's static final, and the inject process is happens after enum loaded – Mạnh Quyết Nguyễn May 23 '18 at 23:58
  • @StefanFalk I think you are right. – ASR4 May 24 '18 at 00:06
  • @MạnhQuyếtNguyễn I have a junit which uses powermock, because of which the code coverage is not showing up. So I was trying to create a wrapper around the class with static methods. Now I am trying to inject this wrapper in the enum, instead of the original class with static methods. – ASR4 May 24 '18 at 00:09
  • 2
    Your `Enum` should not contain logic. If it contains logic, then your design is wrong. Refactoring the logic part out. You test your util class which has static methods is enough. – Mạnh Quyết Nguyễn May 24 '18 at 00:12
  • a `Car` is not a finite designation that is known ahead of time, so an Enum is not an appropriate way to model it in any case. a _Honda_ is an _AutoMaker_, not a _Car_, and you would have to re-build your application when Koenigsegg entered the market. Use a `Class`. – Stephen P May 24 '18 at 00:19
  • @StephenP I used car and honda as examples they are not the names I have actually used, I appreciate your suggestion thanks :) – ASR4 May 24 '18 at 00:27
  • Why has this been marked as duplicate? It is not similar to any of the question feeling unwelcome has marked here. He definitely is very unwelcoming. – ASR4 May 24 '18 at 06:13
  • I disagree with the statement that an `enum` should contain no logic. Check Joshua Bloch's usage of Enums in Effective Java, there are some helpful patterns. – Hein Blöd May 15 '20 at 11:55

1 Answers1

2

You need to create a workaround with an inner static class that will be a Spring component, inject it and set carparts for entire Car EnumSet.

public enum Car {
    private Carparts carparts;

    @Component
    public static class CarPartsInjector {
        @Inject
        private Carparts carparts;

        @PostConstruct
        public void construct() {
            for (Car car: EnumSet.allOf(Car.class))
               car.setCarparts(carparts);
        }

        private void setCarparts(Carparts carparts) {
            this.carparts = carparts;
        }
    //...

}

In general, I think this is not a proper solution.

The problem here is Data Model.

The Car shouldn't be an enum. It thould be a class with list of Carparts, enum as type like CarType or ManufacturerType.

J-Alex
  • 6,881
  • 10
  • 46
  • 64