How to @Inject Enum values into CDI beans

Sep 19, 2012 5:52 PM, Lincoln Baxter III [ Original post ]

I was recently asked how to Inject a Java Enum into a bean constructor using CDI. This turns out to be a fairly interesting situation, because enums are not usually available for Injection.

The first attempt

As much as we would hope for this to work, it does not. Enums are not beans because they have no default constructor (hence CDI does not know how to construct them,) and there is no standard way to resolve which enumerated value should be injected by default (Unless there is only one value, but this is still not supported due to the lack of default constructor.)

Injecting an enum with a single value does not work.
public class InjectedObject {
   private MyEnum e;

   @Inject
   public InjectedObject(MyEnum e) {
      this.e = e;
   }
   
   public MyEnum getValue() {
      return e;
   }

   /**
    * Our enum
    */
   public enum MyEnum {
      ONE
   }
}

This will result in a deployment failure

Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [MyEnum] with qualifiers [@Default] at injection point [[BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject public org.example.InjectedObject(MyEnum)]
 at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:365)
 at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:297)
 at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:157)
 at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:184)
 at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:470)
 at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:74)
 at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:72)
 at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:60)
 at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:53)
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
 at java.util.concurrent.FutureTask.run(FutureTask.java:138)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 ... 1 more

The solution

We must turn to producer methods in order to make this possible. It takes just a little bit of code, but it is possible, and very easy! The reason this works is because any value may be injected if it resolves to a unique set of qualifiers and types. You could even inject a java.lang.String using this technique.

Using @Produces to to inject an enum in CDI.
/**
 * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
 */
public class InjectedObject
{
   private MyEnum e;

   @Inject
   public InjectedObject(MyEnum e)
   {
      this.e = e;
   }

   public MyEnum getValue()
   {
      return e;
   }

   /**
    * A producer is required in order to {@link Inject} an Enum
    */
   @Produces
   public static MyEnum getEnum()
   {
      return MyEnum.THREE;
   }

   /**
    * Our enum
    */
   public enum MyEnum
   {
      ONE, TWO, THREE
   }

}

And there you have it! A perfectly functional method of injecting enum values in CDI. You will, however, need to make sure you know which type of enum you want to inject, and if you need multiple types, then you’ll need to create qualifiers for each value.

You could also use the built-in @Named qualifier

The @Named qualifier is a built in qualifying type that allows unique qualifiers to be created using String values.

Using the @Named qualifier to inject arbitrary values of the same type
/**
 * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
 */
public class InjectedObject
{
   private MyEnum e1;
   private MyEnum e2;

   @Inject
   public InjectedObject(@Named("ONE") MyEnum e1, @Named("TWO") MyEnum e2)
   {
      this.e1 = e1;
      this.e2 = e2;
   }

   public MyEnum getValue1()
   {
      return e1;
   }

   public MyEnum getValue2()
   {
      return e2;
   }

   /**
    * A producer is required in order to {@link Inject} an Enum
    */
   @Produces
   @Named("ONE")
   public static MyEnum getEnumOne()
   {
      return MyEnum.ONE;
   }

   @Produces
   @Named("TWO")
   public static MyEnum getEnumTwo()
   {
      return MyEnum.TWO;
   }

   /**
    * Our enum
    */
   public enum MyEnum
   {
      ONE, TWO, THREE
   }

}

We would not, however, be able to @Inject @Named("THREE") MyEnum e because we have not declared a producer with such a qualifier!

Lincoln Baxter, III

About the author:

Lincoln Baxter, III is a Senior Software Engineer at Red Hat , working on JBoss open-source projects; most notably as project lead for JBoss Forge . This blog represents his personal thoughts and perspectives, not necessarily those of his employer.

He is a founder of OCPsoft , the author of PrettyFaces and Rewrite , the leading URL-rewriting extensions for Servlet, Java EE, and Java web frameworks; he is also the author of PrettyTime , social-style date and timestamp formatting for Java. When he is not swimming, running, or playing Ultimate Frisbee, Lincoln is focused on promoting open-source software and making web-applications more accessible for small businesses, individuals.