“@inject”-ed attribute remains null

2019-04-05 03:25发布

问题:

I am trying to inject a service into my bean but it is always null. I get the following error: WELD-001000 Error resolving property userBean against base null.

Some code snippets:

index.xhtml

<h:body>
    Hello from Facelets
    #{userBean.name}
</h:body>

userbean.java

package beans;

import Domain.User;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import service.UserService;

@Named
@SessionScoped
public class UserBean implements Serializable{
    @Inject UserService service;
    private User user;

    public UserBean(){
        this.user = service.find_user("foo");
    }

    public String getName(){
        return "bar";
    }
}

UserService.java

package service;

import Domain.User;
import javax.ejb.Stateless;
import javax.inject.Named;

@Named
@Stateless
public class UserService {
    public UserService(){}

    public User find_user(String name){
        return new User();
    }
}

回答1:

The error message could be a hint, that the JVM wasn't able to create an instance of UserBean. The following is some guessing and would have to be proven:

Dependecy Injection requires a dependency injector, a tool that injects an instance of UserService into a UserBean. In your code you're already using this injected instance during instantiation of the bean: you call the injected service in the constructor.

If the dependency injector starts it's work after the bean is created, then the call to the service inside the constructor will raise a NullPointerException (because service is still null at that time). It's worth checking that by trying to catch NPEs in the UserBean constructor for a moment. If you catch one - voilà - the dependency injector starts runnning after the bean has been created and, as a consequence, we can't use injected services during class instantiation (= in the constructor)


Workaround idea: implement a small service provider helper class - inner class could work:

public class UserBean implements Serializable {
    static class UserServiceProvider {
      @Inject static UserService service;
    }

    // ... 

    public UserBean() {
      this.user = UserServiceProvider.service.findUser("kaas"); 
    }

    // ...
}

Untested but could work - the service should be injected in the provider class before you use it in the beans constructor.



回答2:

Another alternative is use @PostConstruct method annotation.

@SessionScoped
public class UserBean implements Serializable {
    @Inject UserService service;
    private User user;
    public UserBean() {

    }

   @PostConstruct
    void init(){
        this.user = service.findUser("kaas"); 
    }

  }

Read docs