Search code examples
javadependency-injectioncdijboss-arquillianjava-ee-8

WELD-001408: Unsatisfied dependencies for type Logger with qualifiers @Default at injection point [BackedAnnotatedField] @Inject


I'm having this problem while testing a JavaEE8 application with Arquillian: WELD-001408: Unsatisfied dependencies for type Logger with qualifiers @Default at injection point [BackedAnnotatedField] @Inject private academy.learnprogramming.services.TodoService.LOG

I have the same error for the injected EntityManager

These are my classes:

TodoService.class (the class that I have to test)

package academy.learnprogramming.services;

import academy.learnprogramming.entities.Todo;
import org.apache.log4j.Logger;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.List;

@Transactional
public class TodoService {

    @Inject
    private Logger LOG = Logger.getLogger(TodoService.class);

    @Inject
    EntityManager entityManager;

    public Todo createTodo(Todo todo) {
        //Persist into db
        entityManager.persist(todo);
        return todo;
    }

    public Todo updateTodo(Todo todo) {
        entityManager.merge(todo);
        return todo;
    }

    @PostConstruct
    private void init() {
        LOG.info("Bean TodoService created");
    }

    public Todo findTodoById(Long id) {
        return entityManager.find(Todo.class, id);
    }

    public List<Todo> getTodos(){
        return entityManager.createQuery("SELECT t from Todo t", Todo.class).getResultList();
    }

}

TodoServiceTest.class (The class used for testing)

package academy.learnprogramming.services;

import academy.learnprogramming.config.Producers;
import academy.learnprogramming.entities.Todo;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

@RunWith(Arquillian.class)
public class TodoServiceTest {

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class)
                .addClasses(TodoService.class, Todo.class, Producers.class)
                .addAsResource("persistence.xml", "META-INF/persistence.xml")
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void createTodo() {
    }

    @Test
    public void updateTodo() {
    }

    @Test
    public void findTodoById() {
    }

    @Test
    public void getTodos() {
    }
}

Producers.class (Class used to add 3rd party libraries to CDI)

package academy.learnprogramming.config;


import org.apache.log4j.Logger;
import org.dozer.DozerBeanMapper;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;

//If producers becomes complitated, split it in many classes, each for a single producer
public class Producers {

    @Produces
    @PersistenceContext
    EntityManager entityManager;

    @Produces
    public Logger produceLogger(InjectionPoint injectionPoint) {
        return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
    }

    //Auto mapper
    @Produces
    public DozerBeanMapper produceDozenBeanMapper() {
        DozerBeanMapper mapper = new DozerBeanMapper();
        List<String> mappingFiles = new ArrayList();
        mappingFiles.add("dozerJdk8Converters.xml");
        mapper.setMappingFiles(mappingFiles);
        return mapper;
    }
}

Searching around, I understood that possible problems could be:

  1. beans.xml could give problems if you don't put bean-discovery-mode="all", because it won't scan for not annotated beans, but my beans.xml file has bean-discovery-mode="all"
  2. The Logger and the EntityManager injected into the TodoService class could not have a Producer, but I have the Producers class
  3. People can make mistakes during the import of Logger class for TodoService, TodoServiceTest and Producers classes, having for example import org.apache.log4j.Logger in one class, and java util.logging.Logger for another, but I have all classes with import org.apache.log4j.Logger

If I remove the @Inject annotation and I use the logger from the classes, It works.

What else can I try? Thank you a lot for your time.


Solution

  • Try to use the WebArchive if you use a WAR file

     @Deployment
        public static WebArchive createDeployment() {
            return ShrinkWrap.create(WebArchive.class)
                    .addClasses(TodoService.class, Todo.class, Producers.class)
                    .addAsResource("persistence.xml", "META-INF/persistence.xml")
                    .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }
    

    remove the Logger.getLogger(TodoService.class); the producer it's going to instantiate the logger.

    @RequestScoped
    @Transactional
    public class TodoService {
    
        @Inject
        private Logger log;
    
        @Inject
        EntityManager entityManager;
    
        public Todo createTodo(Todo todo) {
            //Persist into db
            entityManager.persist(todo);
            return todo;
        }
    
        public Todo updateTodo(Todo todo) {
            entityManager.merge(todo);
            return todo;
        }
    
        @PostConstruct
        private void init() {
            log.info("Bean TodoService created");
        }
    
        public Todo findTodoById(Long id) {
            return entityManager.find(Todo.class, id);
        }
    
        public List<Todo> getTodos(){
            return entityManager.createQuery("SELECT t from Todo t", Todo.class).getResultList();
        }