Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Beans and injection

CDI (Contexts and Dependency Injection) is the specification that creates application objects and wires them together. An object managed by CDI is called a bean. Instead of new PostStore(), a class simply declares that it needs a store, and the CDI container creates it and injects it into a field. This way every part of the application gets the same object, and the code does not depend on how that object is built.

Which class becomes a bean

In Jakarta EE a class becomes a bean when it has a scope annotation: @ApplicationScoped, @RequestScoped, @SessionScoped, @Dependent. The store from the previous chapter is already a bean:

// src/main/java/com/example/blog/PostStore.java (fragment)
@ApplicationScoped
public class PostStore {
    // ...
}

You do not need a beans.xml file for this: the server finds classes with these annotations by itself. Jakarta REST resources, servlets and filters are also managed by the container, so injection works in them.

Field injection

The resource gets the store with the @Inject annotation:

// src/main/java/com/example/blog/PostResource.java (fragment)
@Inject
PostStore store;

The same works in a servlet. Create src/main/java/com/example/blog/StatsServlet.java:

// src/main/java/com/example/blog/StatsServlet.java
package com.example.blog;
 
import jakarta.inject.Inject;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet("/stats")
public class StatsServlet extends HttpServlet {
 
    @Inject
    PostStore store;
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        response.setContentType("text/plain; charset=UTF-8");
        response.getWriter().println("Posts in the blog: " + store.findAll().size());
    }
}

The servlet and the REST resource got the same store object. That is easy to check: add a post through the API and look at the counter.

curl http://localhost:8080/blog/stats
curl -H "Content-Type: application/json" -d '{"title":"CDI","body":"Beans and injection."}' http://localhost:8080/blog/api/posts
curl http://localhost:8080/blog/stats
Posts in the blog: 2
{"body":"Beans and injection.","createdAt":"2026-10-04","id":3,"title":"CDI"}
Posts in the blog: 3

Constructor injection

Beans can depend on each other. The publishing service gets the store through its constructor:

// src/main/java/com/example/blog/PostService.java
package com.example.blog;
 
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
 
@ApplicationScoped
public class PostService {
 
    private PostStore store;
 
    protected PostService() {
        // needed by the container to create a proxy
    }
 
    @Inject
    public PostService(PostStore store) {
        this.store = store;
    }
 
    public Post publish(NewPost data) {
        return store.add(data);
    }
}

For @ApplicationScoped beans the container creates a proxy — an intermediary object that forwards calls to the real bean. The proxy needs a no-argument constructor, so next to the @Inject constructor you need protected PostService(). Without it the application fails to start with WELD-001410: The injection point has non-proxyable dependencies. In the resource, replace store.add(data) with a service call:

// src/main/java/com/example/blog/PostResource.java (fragment)
@Inject
PostService service;
 
// in the create method:
Post post = service.publish(data);

Ways to inject

WayExampleWhen it is handy
Field@Inject PostStore store;Resources, servlets, short code
Constructor@Inject PostService(PostStore store)Dependencies are visible at once, easy to test
Method@Inject void setStore(PostStore store)Rarely

Common mistake

Forgetting the scope annotation. If you remove @ApplicationScoped from PostStore, the class is no longer a bean, and the application does not start. The server log shows:

WELD-001408: Unsatisfied dependencies for type PostStore with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject com.example.blog.PostResource.store

"Unsatisfied dependencies" means the container found no matching bean for a field with @Inject.

Thanks for reading!

Donate to the site — we work hard for you.