Jakarta EE
Jakarta EE: La Piattaforma Enterprise Java per il Cloud Native
Jakarta Enterprise Edition (EE) rappresenta l’evoluzione open source di Java EE, progettata specificamente per supportare lo sviluppo di applicazioni enterprise moderne e cloud native. In questo articolo esamineremo in dettaglio la suddetta piattaforma le sue caratteristiche principali, l’ecosistema tecnologico e forniremo una guida pratica per sviluppatori e ingegneri informatici.
Storia e Origini di Jakarta EE
Jakarta EE nasce dalla transizione di Java Enterprise Edition sotto la gestione dell’Eclipse Foundation nel 2017. Questa transizione è avvenuta quando Oracle ha deciso di trasferire le tecnologie Java EE alla Eclipse Foundation per accelerare l’innovazione e lo sviluppo della piattaforma enterprise Java.
Il nome “Jakarta” è un riferimento alla capitale dell’Indonesia e rappresenta simbolicamente un nuovo inizio per la piattaforma enterprise Java. La Eclipse Foundation, insieme a un consorzio di leader dell’industria tecnologica tra cui Fujitsu, IBM, Oracle, Red Hat, e Tomitribe, coordina lo sviluppo e l’evoluzione di Jakarta Enterprise Edition.
L’evoluzione storica della piattaforma può essere tracciata attraverso le seguenti fasi:
- J2EE (Java 2 Enterprise Edition): Le prime versioni della piattaforma enterprise
- Java EE: L’evoluzione moderna sotto Oracle
- Jakarta EE: L’era open source sotto Eclipse Foundation
Caratteristiche Principali e Finalità Jakarta EE
Jakarta Enterprise Edition è progettata per supportare lo sviluppo di applicazioni enterprise scalabili, sicure e affidabili. Le caratteristiche principali includono:
Architettura Modulare
La piattaforma è strutturata in specifiche modulari che possono essere implementate singolarmente o in combinazione, offrendo flessibilità nella costruzione di applicazioni enterprise di diverse dimensioni e complessità.
Cloud Native Support
Jakarta Enterprise Edition è specificamente ottimizzata per ambienti cloud, supportando pattern architetturali moderni come microservizi, containerizzazione e deployment distribuiti.
Backward Compatibility
Mantiene la compatibilità con le applicazioni Java Enterprise Edition esistenti, proteggendo gli investimenti tecnologici e facilitando la migrazione graduale.
Standard Aperti
Basata su specifiche aperte e standard dell’industria, garantisce interoperabilità e prevenzione del vendor lock-in.
I Profili di Jakarta EE
Jakarta Enterprise Edition è organizzata in tre profili principali, ciascuno progettato per specifici casi d’uso e requisiti architetturali:
Jakarta EE Core Profile
Il Core Profile, introdotto con Jakarta EE 10, definisce un sottoinsieme minimal delle specifiche Jakarta Enterprise Edition specificamente progettato per runtime più piccoli. Questo profilo è ottimizzato per:
- Microservizi: Applicazioni di dimensioni ridotte con footprint limitato
- Ahead-of-Time (AOT) Compilation: Supporto per la compilazione nativa con strumenti come GraalVM
- Cloud Native Applications: Applicazioni containerizzate con tempi di startup rapidi
Il Core Profile include le seguenti specifiche essenziali:
- Jakarta CDI (Contexts and Dependency Injection)
- Jakarta RESTful Web Services
- Jakarta JSON Processing e JSON Binding
- Jakarta Annotations
Jakarta EE Web Profile
Il Web Profile rappresenta un sottoinsieme completo della piattaforma Jakarta EE, specificatamente progettato per lo sviluppo di applicazioni web moderne. Include tutte le tecnologie del Core Profile più:
- Jakarta Servlet
- Jakarta Server Pages (JSP)
- Jakarta Server Faces (JSF)
- Jakarta Bean Validation
- Jakarta Persistence (JPA)
- Jakarta Transactions
- Jakarta Security
Questo profilo è ideale per applicazioni web tradizionali che richiedono un set completo di funzionalità enterprise senza la complessità della piattaforma completa.
Jakarta EE Platform (Full Profile)
Il Full Platform include tutte le specifiche Jakarta Enterprise Edition, fornendo il set completo di servizi enterprise. Oltre alle tecnologie dei profili precedenti, include:
- Jakarta Enterprise Beans (EJB)
- Jakarta Message Service (JMS)
- Jakarta Mail
- Jakarta Batch
- Jakarta Concurrency
- Jakarta Connector Architecture
Linguaggi e Competenze Richieste
Linguaggio Principale: Java
Jakarta EE è primariamente sviluppata in Java, richiedendo una solida conoscenza del linguaggio e del suo ecosistema. Le versioni recenti di Jakarta EE supportano:
- Jakarta EE 10: Richiede Java 11 come versione minima
- Jakarta EE 11: Supporta Java 17 come versione di riferimento
Competenze Tecniche Fondamentali
Per sviluppare efficacemente con Jakarta Enterprise Edition, sono necessarie le seguenti competenze:
Architetture Enterprise:
- Pattern architetturali enterprise (MVC, Dependency Injection, Aspect-Oriented Programming)
- Principi di design SOLID
- Architetture a microservizi e SOA
Tecnologie Web:
- Protocolli HTTP/HTTPS
- Architetture RESTful
- Formati di dati JSON e XML
- Tecnologie front-end per l’integrazione
Gestione Dati:
- Database relazionali e SQL
- Object-Relational Mapping (ORM)
- Transazioni ACID
- Ottimizzazione delle query
Sicurezza:
- Autenticazione e autorizzazione
- Crittografia e certificati digitali
- Secure coding practices
- OAuth 2.0 e OpenID Connect
Iniziare un Progetto Jakarta EE
Setup dell’Ambiente di Sviluppo
Per iniziare un progetto Jakarta Enterprise Edition, è necessario configurare un ambiente di sviluppo appropriato:
IDE Consigliato: IntelliJ IDEA Ultimate o Eclipse IDE for Enterprise Java and Web Developers sono le scelte più popolari per lo sviluppo Jakarta Enterprise Edition, offrendo supporto completo per le specifiche e strumenti di debugging avanzati.
Build Tool: Maven è il build tool de facto per progetti Jakarta Enterprise Edition, sebbene Gradle sia una valida alternativa.
Application Server: GlassFish è l’implementation server di riferimento per Jakarta EE, ma sono disponibili alternative come WildFly, Open Liberty, e Payara.
Struttura di Progetto Base Jakarta EE
Un progetto Jakarta Enterprise Edition tipico utilizza la seguente struttura Maven:
my-jakarta-project/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ ├── config/
│ │ │ ├── model/
│ │ │ ├── service/
│ │ │ └── rest/
│ │ ├── resources/
│ │ │ └── META-INF/
│ │ │ └── beans.xml
│ │ └── webapp/
│ │ └── WEB-INF/
│ │ └── web.xml
│ └── test/
│ └── java/
└── target/
Configurazione Maven
Il file pom.xml per un progetto Jakarta EE dovrebbe includere le seguenti dipendenze base:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>jakarta-ee-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jakarta.ee.version>10.0.0</jakarta.ee.version>
</properties>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.ee.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
Sviluppo di RESTful Web Services Jakarta EE
Jakarta Enterprise Edition fornisce Jakarta RESTful Web Services (JAX-RS) per lo sviluppo di servizi web RESTful. Ecco un esempio completo di implementazione:
Configurazione dell’Applicazione REST
package com.example.config;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
@ApplicationPath("/api")
public class RestApplication extends Application {
// La classe è vuota, la configurazione è gestita tramite annotazioni
}
Modello di Dati
package com.example.model;
import jakarta.json.bind.annotation.JsonbProperty;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Email;
public class User {
@JsonbProperty("id")
private Long id;
@NotBlank(message = "Il nome è obbligatorio")
@JsonbProperty("name")
private String name;
@Email(message = "Email non valida")
@JsonbProperty("email")
private String email;
// Costruttori
public User() {}
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getter e Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
Service Layer con CDI
package com.example.service;
import com.example.model.User;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@ApplicationScoped
public class UserService {
private final Map<Long, User> users = new ConcurrentHashMap<>();
private final AtomicLong idCounter = new AtomicLong(1);
public UserService() {
// Dati di esempio per il testing
createUser(new User(null, "Mario Rossi", "mario.rossi@example.com"));
createUser(new User(null, "Luigi Verdi", "luigi.verdi@example.com"));
}
public List<User> getAllUsers() {
return new ArrayList<>(users.values());
}
public Optional<User> getUserById(Long id) {
return Optional.ofNullable(users.get(id));
}
public User createUser(User user) {
Long id = idCounter.getAndIncrement();
user.setId(id);
users.put(id, user);
return user;
}
public Optional<User> updateUser(Long id, User updatedUser) {
if (users.containsKey(id)) {
updatedUser.setId(id);
users.put(id, updatedUser);
return Optional.of(updatedUser);
}
return Optional.empty();
}
public boolean deleteUser(Long id) {
return users.remove(id) != null;
}
}
REST Controller
package com.example.rest;
import com.example.model.User;
import com.example.service.UserService;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
@Inject
private UserService userService;
@GET
public Response getAllUsers() {
List<User> users = userService.getAllUsers();
return Response.ok(users).build();
}
@GET
@Path("/{id}")
public Response getUserById(@PathParam("id") Long id) {
return userService.getUserById(id)
.map(user -> Response.ok(user).build())
.orElse(Response.status(Response.Status.NOT_FOUND).build());
}
@POST
public Response createUser(@Valid User user) {
User createdUser = userService.createUser(user);
return Response.status(Response.Status.CREATED)
.entity(createdUser)
.build();
}
@PUT
@Path("/{id}")
public Response updateUser(@PathParam("id") Long id, @Valid User user) {
return userService.updateUser(id, user)
.map(updatedUser -> Response.ok(updatedUser).build())
.orElse(Response.status(Response.Status.NOT_FOUND).build());
}
@DELETE
@Path("/{id}")
public Response deleteUser(@PathParam("id") Long id) {
boolean deleted = userService.deleteUser(id);
return deleted ?
Response.noContent().build() :
Response.status(Response.Status.NOT_FOUND).build();
}
}
Sicurezza nei Servizi Web RESTful
Jakarta Enterprise Edition fornisce Jakarta Security per implementare meccanismi di sicurezza robusti. Ecco come implementare l’autenticazione e l’autorizzazione:
Configurazione di Sicurezza Base
package com.example.config;
import jakarta.annotation.security.DeclareRoles;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism;
import jakarta.security.enterprise.authentication.mechanism.http.HttpMessageContext;
import jakarta.security.enterprise.AuthenticationStatus;
import jakarta.security.enterprise.credential.UsernamePasswordCredential;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@ApplicationScoped
@DeclareRoles({"USER", "ADMIN"})
public class CustomAuthenticationMechanism implements HttpAuthenticationMechanism {
@Override
public AuthenticationStatus validateRequest(
HttpServletRequest request,
HttpServletResponse response,
HttpMessageContext httpMessageContext) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
// Validazione del token (implementazione semplificata)
if (isValidToken(token)) {
String username = extractUsernameFromToken(token);
String role = extractRoleFromToken(token);
return httpMessageContext.notifyContainerAboutLogin(
username,
Set.of(role)
);
}
}
return httpMessageContext.responseUnauthorized();
}
private boolean isValidToken(String token) {
// Implementazione della validazione del token
return "valid-token-123".equals(token);
}
private String extractUsernameFromToken(String token) {
// Estrazione dell'username dal token
return "user@example.com";
}
private String extractRoleFromToken(String token) {
// Estrazione del ruolo dal token
return "USER";
}
}
REST Controller con Sicurezza
package com.example.rest;
import com.example.model.User;
import com.example.service.UserService;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.security.enterprise.SecurityContext;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
@Path("/secure/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class SecureUserResource {
@Inject
private UserService userService;
@Context
private SecurityContext securityContext;
@GET
@RolesAllowed({"USER", "ADMIN"})
public Response getAllUsers() {
List<User> users = userService.getAllUsers();
return Response.ok(users).build();
}
@POST
@RolesAllowed("ADMIN")
public Response createUser(User user) {
User createdUser = userService.createUser(user);
return Response.status(Response.Status.CREATED)
.entity(createdUser)
.build();
}
@DELETE
@Path("/{id}")
@RolesAllowed("ADMIN")
public Response deleteUser(@PathParam("id") Long id) {
boolean deleted = userService.deleteUser(id);
return deleted ?
Response.noContent().build() :
Response.status(Response.Status.NOT_FOUND).build();
}
@GET
@Path("/profile")
@RolesAllowed({"USER", "ADMIN"})
public Response getCurrentUserProfile() {
String currentUser = securityContext.getCallerPrincipal().getName();
// Logica per recuperare il profilo dell'utente corrente
return Response.ok()
.entity(Map.of("user", currentUser, "authenticated", true))
.build();
}
}
Gestione Exception Personalizzata
package com.example.exception;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import java.util.HashMap;
import java.util.Map;
@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(ConstraintViolationException exception) {
Map<String, String> errors = new HashMap<>();
for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
String propertyPath = violation.getPropertyPath().toString();
String message = violation.getMessage();
errors.put(propertyPath, message);
}
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("status", "error");
errorResponse.put("message", "Errori di validazione");
errorResponse.put("errors", errors);
return Response.status(Response.Status.BAD_REQUEST)
.entity(errorResponse)
.build();
}
}
Ecosystem e Strumenti Jakarta EE
L’ecosistema Jakarta include numerosi strumenti e framework che facilitano lo sviluppo:
Application Servers
- GlassFish: Server di riferimento ufficiale
- WildFly: Server application enterprise di Red Hat
- Open Liberty: Runtime leggero di IBM
- Payara: Fork commerciale di GlassFish
Testing Framework
- Arquillian: Framework per testing di integrazione
- TestContainers: Per testing con container Docker
- JUnit 5: Framework di testing standard per Java
Monitoring e Observability
- MicroProfile Metrics: Metriche standardizzate
- MicroProfile Health: Health checks per applicazioni
- MicroProfile OpenTracing: Distributed tracing
Conclusioni Jakarta EE
L’ecosistema Jakarta rappresenta l’evoluzione naturale delle tecnologie enterprise Java, offrendo una piattaforma robusta, modulare e cloud-ready per lo sviluppo di applicazioni enterprise moderne. La sua architettura a profili permette di scegliere il livello di complessità appropriato per ogni progetto, dal Core Profile per microservizi al Full Platform per applicazioni enterprise complete.
L’adozione di Jakarta Enterprise Edition garantisce:
- Standardizzazione: Basata su specifiche aperte e standard dell’industria
- Portabilità: Applicazioni che funzionano su diversi application server
- Scalabilità: Architettura progettata per carichi enterprise
- Sicurezza: Meccanismi di sicurezza integrati e robusti
- Futuro: Roadmap di sviluppo guidata dalla community
Per sviluppatori e architetti software, Jakarta Enterprise Edition offre un percorso chiaro per modernizzare applicazioni esistenti e sviluppare nuove soluzioni enterprise che sfruttano i benefici del cloud computing mantenendo la solidità e l’affidabilità che caratterizzano la piattaforma Java enterprise.
Innovaformazione, scuola informatica specialistica segue costantemente il mercato IT ed accompagna le aziende nella formazione continua dei team di sviluppatori e DevOps. Trovate l’elenco corsi nell’offerta formativa QUI.
Per altri articoli tecnici consigliamo di navigare sul nostro blog QUI.
Per info e preventivi per le aziende: info@innovaformazione.net – tel. 3471012275 (Dario Carrassi)
Articoli correlati
Claude Code per i droni
Claude Code e Migrazioni SAP
Claude Code controllo remoto
Opportunità Carriera Contabilità SAP
Guida SIA AI
