ling
ling

Reputation: 1675

Dependency Injection and JPA and Hibernate

Class 1: Repository.java:

@ApplicationScoped
public class Repository {

    @Inject
    private EntityManager em;

    public Term findById(Long id) {
        return em.find(Term.class, id);
    }
}

Class 2: Word.java

@Named
@RequestScoped
public class Word {

    @Inject
    private Logger log;

    @Inject
    private Repository repository;

    private Term term;

    public Word() {

    }

    public Word(Long id) {

        try{
            term = this.findTermById(id);       
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    @Produces
    @Named
    public Term getTerm() {

        return term;
    }

    public Term findTermById(Long id) {

        Term term = repository.findById(id);

        if(term==null) {
            log.info("Can't find this word from database: " + term);
        }

        return term;
    }
}

Class 3: Resources.java

public class Resources {
    @Produces
    @PersistenceContext
    private EntityManager em;

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

    @Produces
    @RequestScoped
    public FacesContext produceFacesContext() {
        return FacesContext.getCurrentInstance();
    }
}

The problem with these two classes is that, when running the server, it throws an NullPointerException at the line:

Term term = repository.findById(id);

which means the injection of the object 'repository' failed, since debugging shows that "repository=null".

@Inject
private Repository repository;

Why does the injection is unsuccessful? Thank you.

Upvotes: 0

Views: 2782

Answers (2)

durr
durr

Reputation: 1479

As @Geinmachi said, you are calling it in the constructor but you are not injecting it in the constructor but on field level which is not initialized until @PostConstruct.

You can use constructor injection to inject the repository as a parameter but instead you should not be manually instantiating Word but through CDI injection as well.

@Inject
public Word(Repository repo) {
    this.repo = repo;
}

In general a constructors should never be doing actions (like the db lookup you are doing), it is very bad practice because no one knows the behavior from outside plus you won't have a transaction going during @Inject. Also you should not manually instantiate CDI beans because their lifecycle is managed by CDI and are designed to be used through @Inject.

Also you will have concurrency issues by having an Applicationscoped entitymanager, it should be requestscoped.

Upvotes: 1

newohybat
newohybat

Reputation: 186

Don't you have full stacktrace? I think the NullPointerException might come from private EntityManager em; being null in your Repository bean.

CDI doesn't see your class Resources, as it is not defined bean. (As far as I can tell from the code.)

Upvotes: 0

Related Questions