Creating Java EE apps with CDI in NetBeans

Contexts and Dependency Injection (CDI) is the Jakarta EE standard for assembling enterprise Java applications from collaborating beans. Instead of creating every collaborator inside a servlet or resource class, a component declares what it needs and the container supplies it. This makes bean injection explicit without scattering object construction throughout the code.

NetBeans keeps the project, source editor, Maven goals, application server and debugger close together. The workflow below covers creating a Java EE application with CDI and dependency injection in NetBeans, from an empty Maven project to a running web archive. The same steps suit a small internal service or a larger multi-module application.

Version alignment comes first. Jakarta EE replaced the older Java EE namespace, so javax.enterprise.* examples belong to older runtimes while modern servers use jakarta.enterprise.*. Match the project archetype, JDK, dependency versions and selected server profile before copying code from another tutorial.

Constructor injection, deliberate scopes and an explicit bean-discovery policy form a reliable baseline. Australian teams working across Sydney, Melbourne, Brisbane and Perth can also record the server time zone explicitly—Australia/Sydney, Australia/Perth or UTC—rather than rely on workstation defaults, making daylight-saving transitions easier to interpret. Plain, direct wording and Australian English spelling keep these examples practical for everyday maintenance.

Understanding CDI in a web application

A CDI bean is a managed class that the container can discover, instantiate and inject. @ApplicationScoped suits reusable stateless services; @RequestScoped follows one request through several components. Select a scope according to how long state must live, rather than using it as a substitute for design.

Dependencies are matched by type and, where needed, by qualifier. A constructor dependency with one suitable bean can be injected automatically; ambiguous candidates require a custom qualifier such as @Specialist. Using interfaces also gives tests a clean substitution point.

The NetBeans overview provides useful context for the IDE and enterprise Java tooling. CDI works in a WAR or EAR and can complement EJB session beans or replace explicit EJB lookups in many services. NetBeans coordinates the work; the application server performs bean discovery and injection at runtime.

Setting up the project in NetBeans

In New Project, choose Maven and a WAR archetype whose Jakarta EE level matches the installed server. Enter the project and artefact names, then choose a package such as au.com.example.greeter. Use an EAR only when the deployment genuinely combines several Java EE modules.

Select GlassFish or another supported server in the project properties. The application server supplies the Jakarta EE and CDI APIs at runtime, so avoid bundling duplicate API JARs in the WAR. Check the archetype’s Java release and dependency scopes; Jakarta APIs should normally have provided scope rather than being packaged with the application.

Readers can consult broader ecosystem perspectives for context on the platform. GlassFish is open source and can suit Australian teams managing tight AUD tooling budgets without a commercial server licence, although operating-system images, Java support and patching remain their responsibility. Teams on slower regional NBN links can also use a shared Maven cache to reduce repeated downloads.

Implementing beans and injection points

Start with a small business service whose responsibility is clear. Keep it free of framework-specific lookup calls because CDI will provide its collaborators:

@ApplicationScoped
public class GreetingService {
    public String greet(String name) {
        return "Hello, " + name;
    }
}

Then expose that service through a REST resource and inject it in the constructor:

@Path("/hello")
@RequestScoped
public class HelloResource {
    private final GreetingService greetingService;

    @Inject
    public HelloResource(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GET
    public String hello(@QueryParam("name") String name) {
        return greetingService.greet(name);
    }
}

Both classes need no manual new call from application code because the container creates them. Constructor injection exposes an unsatisfied dependency during deployment and avoids partially initialised objects. Field injection is available, but the constructor makes required services easier to inspect.

Qualifiers distinguish multiple implementations while producers offer configured objects that CDI cannot discover automatically. Add an explicit beans.xml under src/main/webapp/WEB-INF with bean-discovery-mode="annotated" and a namespace matching the runtime. Annotated mode limits discovery to bean-defining annotations, giving the archive predictable behaviour.

Deploying and checking the result

Run the project and NetBeans starts the selected GlassFish profile or deploys to an already running instance. The server output should show a successful deployment before the browser is opened because startup errors are often clearer there.

A clean Maven build also produces the WAR under target, normally target/*.war. Call the endpoint at http://localhost:8080/greeter/hello?name=Ada, adjusting the context and port for the chosen profile. A successful response confirms that routing and CDI instantiation worked.

Place a breakpoint in GreetingService.greet to inspect the injected object and follow the request through the debugger. Related real-time workflows can follow the process for creating a WebSocket endpoint, but should reuse this project configuration rather than creating another application.

Testing and profiling the application

A repeatable review starts with these wiring checks:

  • Every injected type resolves to a bean, producer or CDI built-in.
  • Ambiguous dependencies have an explicit qualifier.
  • Each bean scope matches the lifetime of its state.
  • beans.xml uses the correct namespace and discovery mode.
  • Producers have an appropriate disposal strategy for external resources.

After wiring passes, verify the packaged and running behaviour:

  • mvn clean package succeeds without duplicate API warnings.
  • The WAR includes compiled classes and WEB-INF/beans.xml.
  • GlassFish deploys the archive without bean deployment errors.
  • An HTTP request returns the expected response and status.
  • Log timestamps declare Australia/Sydney, Australia/Perth or UTC.

When persistence joins the application, NetBeans can help with profiling Hibernate SQL statements, exposing N+1 patterns and slow queries. Constructor breakpoints then distinguish CDI wiring problems from business or database delays, producing a dependable diagnostic path from local testing to production-like load.