I want to initialize a collection and fill it with data at the startup of my application. Then I would like to access it everywhere in my application. I want for example that my REST API can access the shared collection that is already populated with data.
I first tried to do it with an startup class annotated with @Startup and @Singleton. When I injected my userService in there I had some problems and because of the advice in this post: @Inject and @PostConstruct not working in singleton pattern I tried to do it with an @ApplicationScoped annotation:
@Named
@ApplicationScoped
public class KwetterApp {
@Inject
private UserService service;
@PostConstruct
public void init() {
try {
User harry = new User("Harry", "harry@outlook.com", "New York", "http://harry.com", "Hi, I'm Harry!", UserType.REGULAR);
User nick = new User("Nick", "nick@outlook.com", "California", "http://nick.com", "Hi, I'm Nick!", UserType.REGULAR);
User jane = new User("Jane", "jane@outlook.com", "Texas", "http://jane.com", "Hi, I'm Jane!", UserType.REGULAR);
Tweet tweet = new Tweet("eating...", harry);
Tweet tweet1 = new Tweet("swimming...", harry);
Tweet tweet2 = new Tweet("jogging...", jane);
harry.addTweet(tweet);
harry.addTweet(tweet1);
jane.addTweet(tweet2);
service.create(harry);
service.create(nick);
service.create(jane);
}
catch (Exception e){
e.printStackTrace();
}
}
public UserService getService() {
return service;
}
}
I inject this class in my rest service:
@RequestScoped
@Path("/user")
public class UserRest {
// @Inject
// private UserService userService;
@Inject
private KwetterApp kwetterApp;
// private KwetterApp kwetterApp = KwetterApp.getInstance();
private UserService userService = kwetterApp.getService();
@GET
@Produces({"application/json"})
public List<User> get() throws UserException {
return userService.getAll();
}
}
When injecting this KwetterApp it leads to the following exception:
StandardWrapperValve[rest.RestApplication]: Servlet.service() for servlet rest.RestApplication threw exception
java.lang.NullPointerException
at rest.UserRest.<init>(UserRest.java:27)
at rest.UserRest$Proxy$_$$_WeldClientProxy.<init>(Unknown Source)
I have an empty beans.xml file with bean-discovery-mode set to 'all'. The CDI framework should recognize my KwetterApp class for injection, right? Why is it null?
Thanks in advance,
Mike
Here
@Inject
private KwetterApp kwetterApp;
private UserService userService = kwetterApp.getService();
I do not think the kwetterApp
field is going to be set before userService
.
CDI
will set that field after the object has been constructed.
An alternative, which should be used anyway, is constructor injection
@RequestScoped
@Path("/user")
public class UserRest {
private KwetterApp kwetterApp;
private UserService userService;
protected UserRest() {}
@Inject
public UserRest(final KwetterApp kwetterApp) {
this.kwetterApp = kwetterApp;
this.userService = kwetterApp.getService();
}
@GET
@Produces({"application/json"})
@Override
public List<User> get() throws UserException {
return userService.getAll();
}
}
A protected
constructor is needed because @RequestScoped
is a normal-scoped bean, and it must be proxiable, as described in the specification.
The only annotation that doesn't require an empty constructor is @Singleton
(from javax.inject
).