In the second part of our series on Jakarta EE libraries, we continue our overview and look at another selection of key technologies. You'll learn when to use which API - and how they help you develop robust and modern Java applications.
Decoupled business logic through Jakarta Enterprise Beans (EJB)
With Jakarta EJB, you can develop distributed, transaction-safe and secure components. The best-known variants are session beans (stateless/stateful) and message-driven beans - ideal for your business logic or event processing.
<dependency> <groupId>jakarta.ejb</groupId> <artifactId>jakarta.ejb-api</artifactId> </dependency>
import jakarta.ejb.Stateless;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@Stateless
public class ProductService {
@PersistenceContext
private EntityManager entityManager;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Product createProduct(String name, Double price) {
Product product = new Product();
product.setName(name);
product.setPrice(price);
entityManager.persist(product);
return product;
}
}
Integrating dynamic content - with Jakarta Expression Language (EL)
Jakarta EL is the bridge between backend logic and UI: Expressions such as ${user.name} you can access Java beans directly in JSF or JSP - ideal for dynamic forms and web content.
<dependency> <groupId>jakarta.el</groupId> <artifactId>jakarta.el-api</artifactId> </dependency>
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class UserBean {
private User user;
public String getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getFirstName() {
return user.firstName();
}
public void getLastName() {
return user.lastName();
}
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>User Information</title>
</h:head>
<h:body>
<h:form>
<h:outputLabel value="First Name:" for="firstName" />
<h:inputText id="firstName" value="#{userBean.firstName}" />
<h:outputLabel value="Last Name:" for="lastName" />
<h:inputText id="lastName" value="#{userBean.lastName}" />
</h:form>
</h:body>
</html>
Cross-sectional functions as if from a construction kit - with interceptors
With Jakarta Interceptors, you can separate logging, auditing or security from the core of your business logic, for example. About @AroundInvoke you access method calls - centrally and reusable.
<dependency> <groupId>jakarta.interceptor</groupId> <artifactId>jakarta.interceptor-api</artifactId> </dependency>
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
@Logging
@Interceptor
public class LoggingInterceptor {
@AroundInvoke
public Object logMethodEntry(InvocationContext context) throws Exception {
String className = context.getTarget().getClass().getSimpleName();
String methodName = context.getMethod().getName();
System.out.println("Entering method: " + className + "." + methodName);
try {
return context.proceed();
} finally {
System.out.println("Exiting method: " + className + "." + methodName);
}
}
}
Easily translate objects into JSON - with Jakarta JSON Binding
With Jakarta JSON Binding you can convert POJOs bidirectionally into JSON and back - with type checking, configuration and automatic serialization.
<dependency> <groupId>jakarta.json.bind</groupId> <artifactId>jakarta.json.bind-api</artifactId> </dependency>
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbBuilder;
import jakarta.json.bind.JsonbConfig;
public class JsonbExample {
public static void main(String[] args) {
JsonbConfig config = new JsonbConfig().withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
// Java-Objekt zu JSON
Person person = new Person("John", "Doe", 30);
String json = jsonb.toJson(person);
System.out.println("Serialized JSON: " + json);
// JSON zu Java-Objekt
String jsonInput = "{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"age\":25}";
Person deserializedPerson = jsonb.fromJson(jsonInput, Person.class);
System.out.println("Deserialized: " + deserializedPerson.getFirstName() + " " + deserializedPerson.getLastName());
}
}
Flexible JSON handling - with Jakarta JSON Processing
With Jakarta JSON Processing (JSON-P) you can build or analyze JSON structures object-based - without any additional library: ideal for REST endpoints, configurations or logs.
<dependency> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> </dependency>
import jakarta.json.Json;
import jakarta.json.JsonObject;
public class JsonpCreateExample {
public static void main(String[] args) {
JsonObject personJson = Json.createObjectBuilder()
.add("firstName", "John")
.add("lastName", "Doe")
.add("age", 30)
.add("email", "john.doe@example.com")
.build();
System.out.println("Created JSON: " + personJson);
}
}
import jakarta.json.*;
import java.io.StringReader;
public class JsonpParseExample {
public static void main(String[] args) {
String jsonInput = "{\"firstName\":\"Jane\",\"lastName\":\"Doe\",\"age\":25,\"email\":\"jane.doe@example.com\"}";
try (JsonReader jsonReader = Json.createReader(new StringReader(jsonInput))) {
JsonObject jsonObject = jsonReader.readObject();
String firstName = jsonObject.getString("firstName");
int age = jsonObject.getInt("age");
System.out.println("Parsed: " + firstName + ", age " + age);
}
}
}
Sending e-mails made easy - with Jakarta Mail
With Jakarta Mail, you can easily send system-side emails from your application - e.g. for order confirmations, system notifications or password resets.
<dependency> <groupId>com.sun.mail</groupId> <artifactId>jakarta.mail</artifactId> </dependency>
import jakarta.mail.*;
import jakarta.mail.internet.*;
import java.util.Properties;
public class MailExample {
public static void main(String[] args) {
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.example.com");
props.put("mail.smtp.port", "587");
Session session = Session.getInstance(props);
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("team@example.com"));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("user@example.com"));
message.setSubject("Deine erste Jakarta-Mail");
message.setText("Diese E-Mail wurde per Jakarta Mail API verschickt.");
Transport.send(message);
System.out.println("E-Mail erfolgreich versendet.");
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
Lightweight components with Jakarta Managed Beans
Simple administration, lifecycle and dependency injection: Managed beans are ideal if you need small, configurable components with little overhead.
<dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> </dependency>
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Named;
import java.io.InputStream;
import java.util.Properties;
@Named
@ApplicationScoped
public class ConfigBean {
private Properties configProperties;
@PostConstruct
public void init() {
configProperties = new Properties();
try (InputStream input = getClass().getClassLoader().getResourceAsStream("config.properties")) {
configProperties.load(input);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getConfigProperty(String key) {
return configProperties.getProperty(key);
}
}
Monitoring with JMX - by Jakarta Management
Do you want to record metrics or monitor components? With Jakarta Management, you can use Java Management Extensions (JMX) to monitor your application at runtime.
<dependency> <groupId>jakarta.management</groupId> <artifactId>jakarta.management-api</artifactId> </dependency>
public interface MemoryMonitorMBean {
long getUsedMemory();
long getMaxMemory();
}
public class MemoryMonitor implements MemoryMonitorMBean {
public long getUsedMemory() {
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
public long getMaxMemory() {
return Runtime.getRuntime().maxMemory();
}
}
import javax.management.*;
import java.lang.management.ManagementFactory;
public class MemoryMonitorExample {
public static void main(String[] args) throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName("com.example:type=MemoryMonitor");
MemoryMonitor monitor = new MemoryMonitor();
mBeanServer.registerMBean(monitor, objectName);
}
}
Asynchronous communication - with Jakarta Messaging (JMS)
With Jakarta Messaging you integrate message-based communication - whether in the point-to-point or publish/subscribe model.
<dependency> <groupId>jakarta.jms</groupId> <artifactId>jakarta.jms-api</artifactId> </dependency>
import jakarta.jms.*;
import javax.naming.InitialContext;
public class SimpleJMSConsumer {
public static void main(String[] args) {
try {
InitialContext ctx = new InitialContext();
ConnectionFactory connectionFactory = (ConnectionFactory) ctx.lookup("jms/ConnectionFactory");
Queue queue = (Queue) ctx.lookup("jms/MyQueue");
try (JMSContext jmsContext = connectionFactory.createContext()) {
JMSConsumer consumer = jmsContext.createConsumer(queue);
String message = consumer.receiveBody(String.class);
System.out.println("Nachricht empfangen: " + message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Structuring web applications - with Jakarta MVC
Jakarta MVC is the front-end counterpart to REST: You get a model-view-controller structure including JAX-RS integration for clean HTML views.
<dependency> <groupId>jakarta.mvc</groupId> <artifactId>jakarta.mvc-api</artifactId> </dependency>
import jakarta.mvc.Controller;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
@Path("greeting")
@Controller
public class GreetingController {
@GET
@Produces("text/html")
public String sayHello() {
return "greeting.jsp";
}
}
Connecting objects and databases - with Jakarta Persistence (JPA)
With Jakarta JPA you map objects to relational tables - including unit-of-work and transaction management.
<dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> </dependency>
import jakarta.persistence.*;
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Person() {}
public Person(String name) {
this.name = name;
}
// Getter / Setter
}
import jakarta.persistence.*;
public class JpaExample {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-pu");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(new Person("Alice"));
em.getTransaction().commit();
Person found = em.find(Person.class, 1L);
System.out.println("Gefundene Person: " + found.getName());
em.close();
emf.close();
}
}
REST APIs made easy - with Jakarta RESTful Web Services (JAX-RS)
REST in enterprise quality: With JAX-RS you develop modern HTTP endpoints - with JSON/XML, content negotiation and integration into other APIs.
<dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> </dependency>
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("hello")
public class HelloWorldService {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayHello() {
return "Hello, JAX-RS!";
}
}
Conclusion: More Jakarta EE? Of course.
This part also shows: Jakarta EE is modular, standardized and practical. You only integrate what you need - without reinventing the wheel.
To be continued ...
In the third and final part, we take another look at other APIs - including Jakarta WebSocket, Security, Server Faces (JSF) and more.
Further links
Jakarta EE is a project of the Eclipse Foundation. The logo is a registered trademark.



