Since I'm struggling on documentation about CDI, I hope this question could become a useful resource for the correct CDI annotations to use in Jersey/Glassfish.
Say we have an application BookStore
:
package my.bookstore;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
@ApplicationPath("/bookstore")
public class BookStore extends ResourceConfig {
public BookStore() {
this.packages("my.bookstore.resource");
}
}
We want to make Book
entities accessible via a RESTful service:
package my.bookstore.entity;
public class Book {
public String isbn;
public String title;
public String author;
public Book(String isbn, String title, String author) {
this.isbn = isbn;
this.title = title;
this.author = author;
}
}
So we need a DAO
to access the datastore:
package my.bookstore.dao;
import my.bookstore.entity.Book;
import java.util.List;
public interface BookDAO {
public List<Book> getAllBooks();
}
And its implementation:
package my.bookstore.dao;
import my.bookstore.entity.Book;
import java.util.List;
import java.util.ArrayList;
public class DefaultBookDAO implements BookDAO {
public List<Book> getAllBooks() {
List<Book> bookList = new ArrayList<>();
list.add(new Book("1234", "Awesome Book", "Some Author"));
return bookList;
}
}
Then I want to inject the DefaultBookDAO
into the RESTful service:
package my.bookstore.resource;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/books")
public class BookResource {
@Inject
BookDAO dao;
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Book> getBooks() {
return this.dao.getAllBooks();
}
}
Now, when deploying the application I get:
Unsatisfied dependencies for type BookDAO with qualifiers @Default
since I need to make CDI aware of it; but how? I tried various combinations of @Named
, @Default
, @Model
, @Singleton
, @Stateless
and many resources such as questions and blog articles have they own interpretation of them.
What are the correct, plain CDI annotation to use to make this injection work in Jersey/Glassfish?
Since it is a service you can annotate your DefaultBookDAO
with @Stateless
.
Then you need an additional class implementing the AbstractBinder
class.
It should look like this for your case:
import org.glassfish.hk2.utilities.binding.AbstractBinder;
public class MyApplicationBinder extends AbstractBinder {
@Override
protected void configure() {
bind(DefaultBookDAO.class).to(BookDAO.class);
}
}
You have to register this class in the class where you extend ResourceConfig
like this:
@ApplicationPath("/bookstore")
public class BookStore extends ResourceConfig {
public BookStore() {
register(new MyApplicationBinder());
this.packages("my.bookstore.resource");
}
}
Then the @Inject
should work.
See also:
To me, it seems that you did not put beans.xml file into your application. With Glassfish 4 (generally with Java EE 7) this file is not required, however, if you omit it, only beans annotated with scope annotations are considered. Therefore, as DefaultBookDAO is not marked by any annotation, it is not considered by CDI as a candidate for injection.
You have 2 options to fix it and make CDI mechanism consider DefaultBookDAO:
@Dependent
annotation on DefaultBookDAO class - this will not change its scope, as @Dependent
is the default scope, but will make CDI to consider this class bean-discovery-mode="all"
In my opinion, the first option is cleaner - you may easily separate code which can be injected and which cannot. But if you want to increase productivity by omitting unnecessary annotations, go with the second option. It is more complicated, but you have to do it only once per module.
Please see this oracle blog post about beans.xml in Java EE 7 and the default behavior if it is omitted.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.