1
votes

I'm trying to implement dependency injection in my Java SE program using weld and I have problems using an application scoped producer. This is a PoC of my problem with minimal code. The MyBean class:

public class MyBean implements Serializable{
  private int value;

  public MyBean(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }

  public void setValue(int value) {
    this.value = value;
  }
}

The injection point:

@Path("api")
public class MyResource implements Serializable {
  @Inject
  private MyBean bean;

  @GET
  @Path("bean")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getBean() {
    return Response.ok(bean).build();
  }
}

The producer that I want it's produced instance be @ApplicationScoped is:

public class BeanProducer {

  @Produces
  @ApplicationScoped
  public MyBean beanProducer(){
    System.out.println("producing");
    return new MyBean(42);
  }
}

And it all bound together in a main class:

public class Main {
  public void main(@Observes ContainerInitialized event) {
    try {
      URI baseUri = UriBuilder.fromUri("http://localhost").port(1234).build();
      ResourceConfig config = new ResourceConfig(MyResource.class)
          .register(JacksonFeature.class);
      SimpleServer server = SimpleContainerFactory.create(baseUri, config);
      System.in.read();
      server.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

When I try to run this, I get following exception:

Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001410: The injection point [BackedAnnotatedField] @Inject @ApplicationScoped private MyResource.bean has non-proxyable dependencies at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:392) at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:293) at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134) at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:167) at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:530) at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68) at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66) 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.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435: Normal scoped bean class MyBean is not proxyable because it has no no-args constructor - Producer Method [MyBean] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces @ApplicationScoped public BeanProducer.beanProducer()]. at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:214) at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:178) at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:390) ... 12 more

If I define a scope for producer, it won't work. If I set the injection point scope as @ApplicationScoped and producer without any scope, it works as I want, means I will have a single instance of the bean in the entire lifecycle of my app.

But setting the scope of the injection point as @ApplicationScoped is the same as default scope, ie. a new instance for each request.

What is the reason behind all of this?

1

1 Answers

1
votes

This happens because @ApplicationScoped is a normal scope, it needs to be proxyable. To be proxyable, you need a no-args constructor.

To clarify one of your points

it works as I want, means I will have a single instance of the bean in the entire lifecycle of my app.

This isn't accurate. Injection points don't define scope, the producer does. There's just no type-safe way to do this in Java, since you can have a producer field.