INTRODUCTION
In this Jakarta EE for Junior Developers lesson, as a first step, we will introduce the Jakarta Contexts and Dependency Injection specification and as a second step we will upgrade our simple application to use Dependency Injection through the @Inject
annotation and to select a default value using the @Default
qualifier.
NEW REQUIREMENTSLet us consider that we have received some new requirements to further enhance our simple web application. Specifically, we have been tasked with ensuring that the Department menu displays an additional option named "None." If the user selects this option, the system must randomly choose one of the available departments (HR, IT, Finance, or Marketing) and assign the new employee to it. The purpose of this task is to meet the requirement that, for accounting purposes, no employee can exist without being assigned to a department.
So now, it’s reasonable to wonder what the most practical and logical way to approach this problem might be. However, before we dive into the practical solution to this question, let’s first provide an explanation of what Dependency Injection is and how the Jakarta EE framework offers all the tools we need to implement such a solution.
Jakarta Contexts and Dependency Injection
According to the Jakarta Contexts and Dependency Injection specification (https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#concepts) Dependency Injection in Jakarta EE is the process by which the application server (the DI container) automatically provides objects (dependencies) that a class needs, rather than the class creating those objects itself. In other words, you don't have to construct dependencies by hand (writing new Employee( ) for example) but can leave the container to inject a reference for you. This simple process comes to action when we use the @Inject annotation.
From above description we realize that the framework takes over the responsibility of creating and managing objects and reversing control from the application code to the container (application server). This concept is called Inversion of Control (IoC). Dependency Injection (DI)
is a design pattern and a key feature of Jakarta EE that simplifies the
development of loosely coupled, modular applications. It allows objects
to obtain their dependencies from an external container (the Jakarta EE
runtime) rather than creating them explicitly in the application code.
In Jakarta EE, Contexts and Dependency Injection (CDI) is the primary framework that enables DI. With DI our code development process gets a lot of extra benefits such smooth replacement of the dependencies with mocks or stubs for unit testing, easy management of components as the application grows and promotion of clean, modular, and maintainable code.
APPLICATION UPGRADE
Coming back to our code, the first thing we need to do is to create the logic for randomly generating a selection for a department. Let's create a new package that will include all the classes that we will create in this lesson. You can name your package com.mycompany.services.
Create an interface with the name DepartmentAssignment inside the newly created package. The interface will include only one method named generateDepartment().
DepartmentAssignment.java
package com.mycompany.services;
public interface DepartmentAssignment {
long generateDepartment();
}
Now we need to write an implementation of the interface.
RandomEmployeeDepartment.java
package com.mycompany.services;
public class RandomEmployeeDepartment implements DepartmentAssignment {
@Override
public long generateDepartment() {
long randomNumber = (long) (Math.random() * 4) + 1;
return randomNumber;
}
}
So far, we have just used simple Java logic for creating an interface and its implementation. Now it is the time to use the DI process and request an object of DepartmentAssignment type. In Jakarta EE, the @Inject annotation is used for dependency Injection (DI). It allows developers to specify that a particular object or resource should be automatically provided (injected) by the Jakarta EE container at runtime, rather than being manually instantiated or managed by the developer. With Jakarta Contexts and Dependency Injection you can inject nearly anything everywhere just by simply using the @Inject annotation.
So now we need to inject a reference of DepartmentAssignment into the Controller Servlet.
@Inject
DepartmentAssignment departmentAssignment;
Please notice also that we have added an extra if-else check because the random department name will be only generated when the user clicks on the None option.
if ("None".equals(dept)) {
department.setDept_id(departmentAssignment.generateDepartment());
} else {
switch (dept) {
case "HR" ->
department.setDept_id(1L);
case "IT" ->
department.setDept_id(2L);
case "Finance" ->
department.setDept_id(3L);
case "Marketing" ->
department.setDept_id(4L);
default -> {
}
}
}
When we execute the application, the @Inject annotation will inform the container that it has to inject a reference of a DepartmentAssignment implementation into the departmentAssignment property. Here is the complete code of the Controller Servlet.
Controller.java
package com.mycompany.controllers;
import com.mycompany.jakartaee.entities.Department;
import com.mycompany.jakartaee.entities.Employee;
import com.mycompany.services.DepartmentAssignment;
import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.SystemException;
import jakarta.transaction.UserTransaction;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
@WebServlet(name = "Controller", urlPatterns = {"/Controller"})
public class Controller extends HttpServlet {
@PersistenceContext
private EntityManager em;
@Resource
private UserTransaction userTransaction;
@Inject
DepartmentAssignment departmentAssignment;
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Long dept_id = null;
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
String email = request.getParameter("email");
String date = request.getParameter("hireDate");
String phoneNumber = request.getParameter("phoneNumber");
Double monthlySalary = Double.valueOf(request.getParameter("monthlySalary"));
String dept = request.getParameter("department");
Department department = new Department();
Employee employee = new Employee();
if ("None".equals(dept)) {
department.setDept_id(departmentAssignment.generateDepartment());
} else {
switch (dept) {
case "HR" ->
department.setDept_id(1L);
case "IT" ->
department.setDept_id(2L);
case "Finance" ->
department.setDept_id(3L);
case "Marketing" ->
department.setDept_id(4L);
default -> {
}
}
}
employee.setFirstName(firstName);
employee.setLastName(lastName);
employee.setMonthlySalary(monthlySalary);
Date dt = null;
try {
dt = new SimpleDateFormat("yyyy-MM-dd").parse(date);
} catch (ParseException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
employee.setHireDate(dt);
employee.setEmail(email);
employee.setPhoneNumber(phoneNumber);
employee.setDepartment(department);
try {
userTransaction.begin();
em.persist(employee);
userTransaction.commit();
} catch (NotSupportedException
| SystemException | RollbackException
| HeuristicMixedException | HeuristicRollbackException
| SecurityException | IllegalStateException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet NewServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>The user " + employee.getFirstName() + " has been registered </h1>");
out.println("</body>");
out.println("</html>");
}
}
Finally, we have to add one more option on the Select html component. Here is the complete code for the JSP as well.
index.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Employee Registration</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body>
<h1 style="text-align: center">Employee Registration Form</h1>
<div class="container mt-5">
<section>
<form action="Controller" method="post">
<div class="row">
<div class="col-md-6 mb-3">
<label for="firstname" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstname"
placeholder="Enter your first name" name="firstName" >
</div>
<div class="col-md-6 mb-3">
<label for="lastname" class="form-label">Last Name</label>
<input type="text" class="form-control" id="lastname"
placeholder="Enter your last name" name="lastName" >
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="email" class="form-label">Enter your email</label>
<input type="email" class="form-control" id="email"
placeholder="Enter your email" name="email" >
</div>
<div class="col-md-6 mb-3">
<label for="phone" class="form-label">Enter your Phone number</label>
<input type="text" class="form-control" id="phone"
placeholder="Enter your phone number" name="phoneNumber" >
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="date" class="form-label">Enter the hire date</label>
<input type="date" class="form-control" id="date"
placeholder="Enter the hire date" name = "hireDate" >
</div>
<div class="col-md-6 mb-3">
<label for="salary" class="form-label">Monthly Salary</label>
<input type="number" class="form-control" id="salary"
placeholder="Enter yout salary" name = "monthlySalary" >
</div>
<div class="col-md-6 mb-3">
<label for="department" class="form-label">Department</label>
<select class="custom-select" id="department" name="department">
<option value="HR">HR</option>
<option value="IT">IT</option>
<option value="Finance">Finance</option>
<option value="Marketing">Marketing</option>
<option value="None">None</option>
</select>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</section>
</div>
</body>
</html>
Run the application and register few new employees using the None option for the department. Execute a select statement on the Employees table and notice that each new employee has a random department assign to him.


The Default Qualifier
The @Default
qualifier in Jakarta EE is a built-in qualifier provided by the Contexts and Dependency Injection (CDI) specification. It is used to identify the default bean for a particular type when no other qualifier is explicitly specified. In our example, there is no need to specify a Default qualifier because there is only one implementation of the interface.
In Jakarta EE, if multiple beans of the same type exist, and no explicit qualifier is provided at the injection point, the container uses the bean marked with the @Default
qualifier. If no specific qualifiers are assigned to a bean, it is implicitly assigned the @Default
qualifier by the container.
Our application should work without any issues even if we add the @Default qualifier. If we do not add it the framework assumes that is the step we desire to follow and uses it by default.RandomEmploymentDepartment.java
package com.mycompany.services;
import jakarta.enterprise.inject.Default;
@Default
public class RandomEmployeeDepartment implements DepartmentAssignment {
@Override
public long generateDepartment() {
long randomNumber = (long) (Math.random() * 4) + 1;
return randomNumber;
}
}
Also, we need to add the @Default annotation on the @Inject reference on the Controller.
Controller.java
package com.mycompany.controllers;
import com.mycompany.jakartaee.entities.Department;
import com.mycompany.jakartaee.entities.Employee;
import com.mycompany.services.DepartmentAssignment;
import jakarta.annotation.Resource;
import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.SystemException;
import jakarta.transaction.UserTransaction;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
@WebServlet(name = "Controller", urlPatterns = {"/Controller"})
public class Controller extends HttpServlet {
@PersistenceContext
private EntityManager em;
@Resource
private UserTransaction userTransaction;
@Inject
@Default
DepartmentAssignment departmentAssignment;
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Long dept_id = null;
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
String email = request.getParameter("email");
String date = request.getParameter("hireDate");
String phoneNumber = request.getParameter("phoneNumber");
Double monthlySalary = Double.valueOf(request.getParameter("monthlySalary"));
String dept = request.getParameter("department");
Department department = new Department();
Employee employee = new Employee();
if ("None".equals(dept)) {
department.setDept_id(departmentAssignment.generateDepartment());
} else {
switch (dept) {
case "HR" ->
department.setDept_id(1L);
case "IT" ->
department.setDept_id(2L);
case "Finance" ->
department.setDept_id(3L);
case "Marketing" ->
department.setDept_id(4L);
default -> {
}
}
}
employee.setFirstName(firstName);
employee.setLastName(lastName);
employee.setMonthlySalary(monthlySalary);
Date dt = null;
try {
dt = new SimpleDateFormat("yyyy-MM-dd").parse(date);
} catch (ParseException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
employee.setHireDate(dt);
employee.setEmail(email);
employee.setPhoneNumber(phoneNumber);
employee.setDepartment(department);
try {
userTransaction.begin();
em.persist(employee);
userTransaction.commit();
} catch (NotSupportedException
| SystemException | RollbackException
| HeuristicMixedException | HeuristicRollbackException
| SecurityException | IllegalStateException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet NewServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>The user " + employee.getFirstName() + " has been registered </h1>");
out.println("</body>");
out.println("</html>");
}
}
Our application runs with no issues and assigns a random department to an employee that has no department selected.
full-width
0 Comments
What do you think about Ground of Code?