3

I'm trying to implement Java EE's managed executor ManagedExecutorService to submit callable tasks, where each task makes a call to an injected bean method.

I'm using the Instance class to make the container aware of the task object, but when get() is executed the following exception is thrown:

Caused by: javax.ejb.EJBException: org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type MyTask with qualifiers @Default

I'm running this on WildFly 14.

The injected bean:

@Stateless
public class MyBean {

    public void print() {
        System.out.println("MyBean printed");
    }
}

The task:

@Stateless
public class MyTask implements Callable<String> {

    @Inject
    MyBean myBean;

    @Override
    public String call() throws Exception {

        System.out.println("MyTask called");
        myBean.print();
        return "Task called";

    }
}

The task invoker:

@Stateless
public class TestBean {

    @Inject
    Instance<MyTask> myTaskInstance;

    @Resource
    private ManagedExecutorService executor;

    public void test() throws InterruptedException, ExecutionException {

        List<Callable<String>> tasks = new ArrayList<>(); 
        MyTask task = myTaskInstance.get();  // <------- Exception is thrown here
        tasks.add(task);
        MyTask task2 = myTaskInstance.get();
        tasks.add(task2);

        List<Future<String>> taskResults = null;
        taskResults = executor.invokeAll(tasks);

        List<String> results = new ArrayList<>(); 

        for(Future<String> taskResult : taskResults) {
                results.add(taskResult.get());
        }

    }
}

Why is the exception thrown and how to fix this problem? Is there a library missing in the classpath?

Scott Kurz
  • 4,985
  • 1
  • 18
  • 40
ps0604
  • 1,227
  • 23
  • 133
  • 330

1 Answers1

2

The problem is that with MyTask as an EJB implementing Callable, you've removed the MyTask class itself from the "bean type" of this bean, which means it can't be injected into @Inject MyTask xxx "client", according to the rules in the CDI 2.0 spec:

18.2.2. Bean types of a session bean

The unrestricted set of bean types for a session bean contains all local interfaces of the bean and their superinterfaces. If the session bean has a no-interface view, the unrestricted set of bean types contains the bean class and all superclasses. In addition, java.lang.Object is a bean type of every session bean.

That's why Weld doesn't find a valid MyTask bean to satisfy the injection into your TestBean client.

You can give the MyTask EJB a no-interface view by adding the @LocalBean annotation, e.g.:

@Stateless
@LocalBean
public class MyTask implements Callable<String> {

Or, you can remove the implements Callable and refactor like:

public class MyTask {

    @Inject
    MyBean myBean;

    MyCallable callable = new MyCallable();

    public Callable getCallable() {
        return callable;
    }

    private class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {

            System.out.println("MyTask called");
            myBean.print();
            return "Task called";
        }
    }
}    

public class TestBean {

    // ...

    MyTask task = myTaskInstance.get(); 
    tasks.add(task.getCallable())

    // ...
}

See here for a quick reference on the no-interface view, as well as this post for more discussion.

Scott Kurz
  • 4,985
  • 1
  • 18
  • 40