Stormcloud
Stormcloud

Reputation: 2307

Using Spring injection inside a Java enum

I have a situation where my application can be in exactly one of a several "modes". Since these are discrete values I'd like to model them using an enum type.

With each state my application needs to perform a slightly different functionality, which I'd like to model using the plug-in pattern. I've defined an interface and provided a few implementations.

I'd now like my enumeration to return the plug-in that is appropriate for it's state. I'd like to do the following:

public enum Mode {
  ONE {
    @Override
    public MyType get() { return factory.getFirst(); }
  },
  TWO {
    @Override
    public MyType get() { return factory.getSecond(); }
  };

  @Autowired private MyTypeFactory factory;

  public abstract MyType get();

  // Other methods removed for clarity
}

However this isn't going to work. This is because I'm using spring injection to add the plug-in factory to the enum (enum constants are static and spring injected variables are instance variables so I'll get a compilation error)

I can't create the MyType instances directly from the enum because they will require dependency injection

How do I get around this?

Upvotes: 4

Views: 5431

Answers (1)

Stormcloud
Stormcloud

Reputation: 2307

This probably isn't the best solution (and I'd love to see something better suggested), but this is what I did in the end:

Modify the Factory so it reads:

public class MyTypeFactory {
  private static MyTypeFactory me;

  @PostConstruct
  public void initialise() {
    if (me == null) {
        me = this;
    }
  }

  public static MyTypeFactory getInstance() {
    return me;
  }

  // The same code as before - getFirst(), getSecond() etc
}

So, a (singleton) spring managed bean that looks a bit like an old GOF singleton! The important difference is that there is a publicly accessible default (no argument) constructor

I can then modify my enum to read:

public enum Mode {
  ONE {
    @Override
    public MyType get() { Factory.getInstance().getFirst(); }
  },
  TWO {
    @Override
    public MyType get() { Factory.getInstance().getSecond(); }
  };

  public abstract MyType get();

  // Other methods removed for clarity
}

The enum can get access the factory via the static getInstance method when get() is called

Upvotes: 5

Related Questions