From 495fd4da9556a171295bb8ce28aca223dc4082f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:56:51 +0000 Subject: [PATCH 1/3] Initial plan From d074e792b9c935295878c23a0bc2871d4e9b9c02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:01:27 +0000 Subject: [PATCH 2/3] Add enterprise category with Servlet vs JAX-RS, EJB vs CDI, JDBC vs JPA patterns Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com> --- content/enterprise/ejb-vs-cdi.json | 54 +++ content/enterprise/jdbc-vs-jpa.json | 54 +++ content/enterprise/servlet-vs-jaxrs.json | 54 +++ .../compact-canonical-constructor.json | 2 +- html-generators/generate.py | 3 +- site/enterprise/ejb-vs-cdi.html | 383 +++++++++++++++++ site/enterprise/jdbc-vs-jpa.html | 385 +++++++++++++++++ site/enterprise/servlet-vs-jaxrs.html | 389 ++++++++++++++++++ site/styles.css | 1 + templates/index.html | 1 + 10 files changed, 1324 insertions(+), 2 deletions(-) create mode 100644 content/enterprise/ejb-vs-cdi.json create mode 100644 content/enterprise/jdbc-vs-jpa.json create mode 100644 content/enterprise/servlet-vs-jaxrs.json create mode 100644 site/enterprise/ejb-vs-cdi.html create mode 100644 site/enterprise/jdbc-vs-jpa.html create mode 100644 site/enterprise/servlet-vs-jaxrs.html diff --git a/content/enterprise/ejb-vs-cdi.json b/content/enterprise/ejb-vs-cdi.json new file mode 100644 index 0000000..19fe36c --- /dev/null +++ b/content/enterprise/ejb-vs-cdi.json @@ -0,0 +1,54 @@ +{ + "id": 99, + "slug": "ejb-vs-cdi", + "title": "EJB versus CDI", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "EJB", + "modernApproach": "CDI Bean", + "oldCode": "@Stateless\npublic class OrderEJB {\n @EJB\n private InventoryEJB inventory;\n\n public void placeOrder(Order order) {\n // container-managed transaction\n inventory.reserve(order.getItem());\n }\n}", + "modernCode": "@ApplicationScoped\npublic class OrderService {\n @Inject\n private InventoryService inventory;\n\n @Transactional\n public void placeOrder(Order order) {\n inventory.reserve(order.getItem());\n }\n}", + "summary": "Replace heavyweight EJBs with lightweight CDI beans for dependency injection and transactions.", + "explanation": "CDI (Contexts and Dependency Injection) provides the same dependency injection and transaction management as EJBs, but as plain Java classes with no container-specific interfaces or superclasses. Scopes like @ApplicationScoped and @RequestScoped control lifecycle, and @Transactional replaces mandatory EJB transaction semantics.", + "whyModernWins": [ + { + "icon": "πŸͺΆ", + "title": "Lightweight", + "desc": "CDI beans are plain Java classes with no EJB-specific interfaces or descriptors." + }, + { + "icon": "πŸ’‰", + "title": "Unified injection", + "desc": "@Inject works for every managed bean, JAX-RS resources, and Jakarta EE components alike." + }, + { + "icon": "πŸ§ͺ", + "title": "Easy unit testing", + "desc": "Plain classes without EJB proxy overhead are straightforward to instantiate and mock." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/servlet-vs-jaxrs", + "next": "enterprise/jdbc-vs-jpa", + "related": [ + "enterprise/servlet-vs-jaxrs", + "enterprise/jdbc-vs-jpa", + "language/records-for-data-classes" + ], + "docs": [ + { + "title": "Jakarta CDI Specification", + "href": "https://jakarta.ee/specifications/cdi/" + }, + { + "title": "Jakarta Transactions β€” @Transactional", + "href": "https://jakarta.ee/specifications/transactions/" + } + ] +} diff --git a/content/enterprise/jdbc-vs-jpa.json b/content/enterprise/jdbc-vs-jpa.json new file mode 100644 index 0000000..b5513c9 --- /dev/null +++ b/content/enterprise/jdbc-vs-jpa.json @@ -0,0 +1,54 @@ +{ + "id": 100, + "slug": "jdbc-vs-jpa", + "title": "JDBC versus JPA", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "JDBC", + "modernApproach": "JPA EntityManager", + "oldCode": "String sql = \"SELECT * FROM users WHERE id = ?\";\ntry (Connection con = dataSource.getConnection();\n PreparedStatement ps =\n con.prepareStatement(sql)) {\n ps.setLong(1, id);\n ResultSet rs = ps.executeQuery();\n if (rs.next()) {\n User u = new User();\n u.setId(rs.getLong(\"id\"));\n u.setName(rs.getString(\"name\"));\n }\n}", + "modernCode": "@PersistenceContext\nEntityManager em;\n\npublic User findUser(Long id) {\n return em.find(User.class, id);\n}\n\npublic List findByName(String name) {\n return em.createQuery(\n \"SELECT u FROM User u WHERE u.name = :name\",\n User.class)\n .setParameter(\"name\", name)\n .getResultList();\n}", + "summary": "Replace verbose JDBC boilerplate with JPA's object-relational mapping and EntityManager.", + "explanation": "JPA (Jakarta Persistence API) maps Java objects to database rows, eliminating manual ResultSet processing and SQL string concatenation. EntityManager provides find(), persist(), and JPQL queries so you work with domain objects instead of raw SQL, while the container manages connection pooling and transactions.", + "whyModernWins": [ + { + "icon": "πŸ—ΊοΈ", + "title": "Object mapping", + "desc": "Entities are plain annotated classes β€” no manual ResultSet-to-object translation." + }, + { + "icon": "πŸ”’", + "title": "Type-safe queries", + "desc": "JPQL operates on entity types and fields rather than raw table and column strings." + }, + { + "icon": "⚑", + "title": "Built-in caching", + "desc": "First- and second-level caches reduce database round-trips automatically." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/ejb-vs-cdi", + "next": null, + "related": [ + "enterprise/servlet-vs-jaxrs", + "enterprise/ejb-vs-cdi", + "io/try-with-resources-effectively-final" + ], + "docs": [ + { + "title": "Jakarta Persistence Specification", + "href": "https://jakarta.ee/specifications/persistence/" + }, + { + "title": "Jakarta Persistence 3.1 API", + "href": "https://jakarta.ee/specifications/persistence/3.1/apidocs/" + } + ] +} diff --git a/content/enterprise/servlet-vs-jaxrs.json b/content/enterprise/servlet-vs-jaxrs.json new file mode 100644 index 0000000..b23e828 --- /dev/null +++ b/content/enterprise/servlet-vs-jaxrs.json @@ -0,0 +1,54 @@ +{ + "id": 98, + "slug": "servlet-vs-jaxrs", + "title": "Servlet versus JAX-RS", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "HttpServlet", + "modernApproach": "JAX-RS Resource", + "oldCode": "@WebServlet(\"/users\")\npublic class UserServlet extends HttpServlet {\n @Override\n protected void doGet(HttpServletRequest req,\n HttpServletResponse res)\n throws ServletException, IOException {\n String id = req.getParameter(\"id\");\n res.setContentType(\"application/json\");\n res.getWriter().write(\"{\\\"id\\\":\\\"\" + id + \"\\\"}\");\n }\n}", + "modernCode": "@Path(\"/users\")\npublic class UserResource {\n @GET\n @Produces(MediaType.APPLICATION_JSON)\n public Response getUser(\n @QueryParam(\"id\") String id) {\n return Response.ok(new User(id)).build();\n }\n}", + "summary": "Replace verbose HttpServlet boilerplate with declarative JAX-RS resource classes.", + "explanation": "JAX-RS (Jakarta RESTful Web Services) lets you expose REST endpoints using simple annotations like @GET, @Path, and @Produces. No more manual parsing of request parameters or setting content types on the response β€” the runtime handles marshalling and routing automatically.", + "whyModernWins": [ + { + "icon": "πŸ“", + "title": "Declarative routing", + "desc": "Annotations define HTTP method, path, and content type instead of imperative if/else dispatch." + }, + { + "icon": "πŸ”„", + "title": "Automatic marshalling", + "desc": "Return POJOs directly; the runtime serialises them to JSON or XML based on @Produces." + }, + { + "icon": "πŸ§ͺ", + "title": "Easier testing", + "desc": "Resource classes are plain Java objects, testable without a servlet container." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "language/compact-canonical-constructor", + "next": "enterprise/ejb-vs-cdi", + "related": [ + "enterprise/ejb-vs-cdi", + "enterprise/jdbc-vs-jpa", + "io/http-client" + ], + "docs": [ + { + "title": "Jakarta RESTful Web Services Specification", + "href": "https://jakarta.ee/specifications/restful-ws/" + }, + { + "title": "Jakarta REST 3.1 API", + "href": "https://jakarta.ee/specifications/restful-ws/3.1/apidocs/" + } + ] +} diff --git a/content/language/compact-canonical-constructor.json b/content/language/compact-canonical-constructor.json index 966d77e..07d16cf 100644 --- a/content/language/compact-canonical-constructor.json +++ b/content/language/compact-canonical-constructor.json @@ -35,7 +35,7 @@ "description": "Widely available since JDK 16 (March 2021)" }, "prev": "language/static-members-in-inner-classes", - "next": null, + "next": "enterprise/servlet-vs-jaxrs", "related": [ "language/records-for-data-classes", "language/flexible-constructor-bodies", diff --git a/html-generators/generate.py b/html-generators/generate.py index 6b5a641..fcf6f5a 100644 --- a/html-generators/generate.py +++ b/html-generators/generate.py @@ -30,6 +30,7 @@ "datetime": "Date/Time", "security": "Security", "tooling": "Tooling", + "enterprise": "Enterprise", } @@ -66,7 +67,7 @@ def load_all_snippets(): snippets = {} categories = [ "language", "collections", "strings", "streams", "concurrency", - "io", "errors", "datetime", "security", "tooling", + "io", "errors", "datetime", "security", "tooling", "enterprise", ] json_files = [] for cat in categories: diff --git a/site/enterprise/ejb-vs-cdi.html b/site/enterprise/ejb-vs-cdi.html new file mode 100644 index 0000000..288e8d5 --- /dev/null +++ b/site/enterprise/ejb-vs-cdi.html @@ -0,0 +1,383 @@ + + + + + + EJB versus CDI | java.evolved + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ Enterprise + intermediate +
+

EJB versus CDI

+

Replace heavyweight EJBs with lightweight CDI beans for dependency injection and transactions.

+
+ +
+ +
+
+
+ βœ• Java EE + +
+
+
@Stateless
+public class OrderEJB {
+    @EJB
+    private InventoryEJB inventory;
+
+    public void placeOrder(Order order) {
+        // container-managed transaction
+        inventory.reserve(order.getItem());
+    }
+}
+
+
+
+
+ βœ“ Jakarta EE 8+ + +
+
+
@ApplicationScoped
+public class OrderService {
+    @Inject
+    private InventoryService inventory;
+
+    @Transactional
+    public void placeOrder(Order order) {
+        inventory.reserve(order.getItem());
+    }
+}
+
+
+
+
+ +
+ +
+
+
πŸͺΆ
+

Lightweight

+

CDI beans are plain Java classes with no EJB-specific interfaces or descriptors.

+
+
+
πŸ’‰
+

Unified injection

+

@Inject works for every managed bean, JAX-RS resources, and Jakarta EE components alike.

+
+
+
πŸ§ͺ
+

Easy unit testing

+

Plain classes without EJB proxy overhead are straightforward to instantiate and mock.

+
+
+
+ +
+
+
Old Approach
+
EJB
+
+
+
Modern Approach
+
CDI Bean
+
+
+
Since JDK
+
11
+
+
+
Difficulty
+
intermediate
+
+
+ +
+ +
+
EJB versus CDI
+ Available +

Widely available since Jakarta EE 8 / Java 11

+
+
+ +
+ +

CDI (Contexts and Dependency Injection) provides the same dependency injection and transaction management as EJBs, but as plain Java classes with no container-specific interfaces or superclasses. Scopes like @ApplicationScoped and @RequestScoped control lifecycle, and @Transactional replaces mandatory EJB transaction semantics.

+
+ +
+ + +
+ + +
+ + + +
+ + + + + +
+ + + + + + \ No newline at end of file diff --git a/site/enterprise/jdbc-vs-jpa.html b/site/enterprise/jdbc-vs-jpa.html new file mode 100644 index 0000000..748609c --- /dev/null +++ b/site/enterprise/jdbc-vs-jpa.html @@ -0,0 +1,385 @@ + + + + + + JDBC versus JPA | java.evolved + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ Enterprise + intermediate +
+

JDBC versus JPA

+

Replace verbose JDBC boilerplate with JPA's object-relational mapping and EntityManager.

+
+ +
+ +
+
+
+ βœ• Java EE + +
+
+
String sql = "SELECT * FROM users WHERE id = ?";
+try (Connection con = dataSource.getConnection();
+     PreparedStatement ps =
+             con.prepareStatement(sql)) {
+    ps.setLong(1, id);
+    ResultSet rs = ps.executeQuery();
+    if (rs.next()) {
+        User u = new User();
+        u.setId(rs.getLong("id"));
+        u.setName(rs.getString("name"));
+    }
+}
+
+
+
+
+ βœ“ Jakarta EE 8+ + +
+
+
@PersistenceContext
+EntityManager em;
+
+public User findUser(Long id) {
+    return em.find(User.class, id);
+}
+
+public List<User> findByName(String name) {
+    return em.createQuery(
+        "SELECT u FROM User u WHERE u.name = :name",
+        User.class)
+        .setParameter("name", name)
+        .getResultList();
+}
+
+
+
+
+ +
+ +
+
+
πŸ—ΊοΈ
+

Object mapping

+

Entities are plain annotated classes β€” no manual ResultSet-to-object translation.

+
+
+
πŸ”’
+

Type-safe queries

+

JPQL operates on entity types and fields rather than raw table and column strings.

+
+
+
⚑
+

Built-in caching

+

First- and second-level caches reduce database round-trips automatically.

+
+
+
+ +
+
+
Old Approach
+
JDBC
+
+
+
Modern Approach
+
JPA EntityManager
+
+
+
Since JDK
+
11
+
+
+
Difficulty
+
intermediate
+
+
+ +
+ +
+
JDBC versus JPA
+ Available +

Widely available since Jakarta EE 8 / Java 11

+
+
+ +
+ +

JPA (Jakarta Persistence API) maps Java objects to database rows, eliminating manual ResultSet processing and SQL string concatenation. EntityManager provides find(), persist(), and JPQL queries so you work with domain objects instead of raw SQL, while the container manages connection pooling and transactions.

+
+ +
+ + +
+ + +
+ + + +
+ + + + + +
+ + + + + + \ No newline at end of file diff --git a/site/enterprise/servlet-vs-jaxrs.html b/site/enterprise/servlet-vs-jaxrs.html new file mode 100644 index 0000000..0522865 --- /dev/null +++ b/site/enterprise/servlet-vs-jaxrs.html @@ -0,0 +1,389 @@ + + + + + + Servlet versus JAX-RS | java.evolved + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ Enterprise + intermediate +
+

Servlet versus JAX-RS

+

Replace verbose HttpServlet boilerplate with declarative JAX-RS resource classes.

+
+ +
+ +
+
+
+ βœ• Java EE + +
+
+
@WebServlet("/users")
+public class UserServlet extends HttpServlet {
+    @Override
+    protected void doGet(HttpServletRequest req,
+                         HttpServletResponse res)
+            throws ServletException, IOException {
+        String id = req.getParameter("id");
+        res.setContentType("application/json");
+        res.getWriter().write("{\"id\":\"" + id + "\"}");
+    }
+}
+
+
+
+
+ βœ“ Jakarta EE 8+ + +
+
+
@Path("/users")
+public class UserResource {
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getUser(
+            @QueryParam("id") String id) {
+        return Response.ok(new User(id)).build();
+    }
+}
+
+
+
+
+ +
+ +
+
+
πŸ“
+

Declarative routing

+

Annotations define HTTP method, path, and content type instead of imperative if/else dispatch.

+
+
+
πŸ”„
+

Automatic marshalling

+

Return POJOs directly; the runtime serialises them to JSON or XML based on @Produces.

+
+
+
πŸ§ͺ
+

Easier testing

+

Resource classes are plain Java objects, testable without a servlet container.

+
+
+
+ +
+
+
Old Approach
+
HttpServlet
+
+
+
Modern Approach
+
JAX-RS Resource
+
+
+
Since JDK
+
11
+
+
+
Difficulty
+
intermediate
+
+
+ +
+ +
+
Servlet versus JAX-RS
+ Available +

Widely available since Jakarta EE 8 / Java 11

+
+
+ +
+ +

JAX-RS (Jakarta RESTful Web Services) lets you expose REST endpoints using simple annotations like @GET, @Path, and @Produces. No more manual parsing of request parameters or setting content types on the response β€” the runtime handles marshalling and routing automatically.

+
+ +
+ + +
+ + +
+ + + +
+ + + + + +
+ + + + + + \ No newline at end of file diff --git a/site/styles.css b/site/styles.css index 130e38b..8983ab7 100644 --- a/site/styles.css +++ b/site/styles.css @@ -464,6 +464,7 @@ nav { .badge.datetime { color: var(--accent); background: rgba(251, 146, 60, .1); border-color: rgba(251, 146, 60, .2); } .badge.security { color: var(--pink); background: rgba(244, 114, 182, .1); border-color: rgba(244, 114, 182, .2); } .badge.tooling { color: var(--blue); background: rgba(96, 165, 250, .1); border-color: rgba(96, 165, 250, .2); } +.badge.enterprise { color: var(--cyan); background: rgba(34, 211, 238, .1); border-color: rgba(34, 211, 238, .2); } .badge.beginner { color: var(--green); background: rgba(52, 211, 153, .1); border-color: rgba(52, 211, 153, .2); } .badge.intermediate { color: var(--yellow); background: rgba(251, 191, 36, .1); border-color: rgba(251, 191, 36, .2); } diff --git a/templates/index.html b/templates/index.html index d5e1dbe..77a1a07 100644 --- a/templates/index.html +++ b/templates/index.html @@ -239,6 +239,7 @@

All comparisons

+
diff --git a/site/enterprise/jpa-vs-jakarta-data.html b/site/enterprise/jpa-vs-jakarta-data.html new file mode 100644 index 0000000..77110a4 --- /dev/null +++ b/site/enterprise/jpa-vs-jakarta-data.html @@ -0,0 +1,397 @@ + + + + + + JPA versus Jakarta Data | java.evolved + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ Enterprise + intermediate +
+

JPA versus Jakarta Data

+

Declare a repository interface and let Jakarta Data generate the DAO implementation automatically.

+
+ +
+ +
+
+
+ βœ• Jakarta EE 8+ + +
+
+
@PersistenceContext
+EntityManager em;
+
+public User findById(Long id) {
+    return em.find(User.class, id);
+}
+
+public List<User> findByName(String name) {
+    return em.createQuery(
+        "SELECT u FROM User u WHERE u.name = :name",
+        User.class)
+        .setParameter("name", name)
+        .getResultList();
+}
+
+public void save(User user) {
+    em.persist(user);
+}
+
+
+
+
+ βœ“ Jakarta EE 11+ + +
+
+
@Repository
+public interface Users extends CrudRepository<User, Long> {
+    List<User> findByName(String name);
+}
+
+
+
+
+ +
+ +
+
+
πŸͺ„
+

Zero boilerplate

+

Declare the interface; the container generates the full DAO implementation at deploy time.

+
+
+
πŸ”
+

Derived queries

+

Method names like findByNameAndStatus are parsed automatically β€” no JPQL or SQL needed.

+
+
+
πŸ”Œ
+

Portable

+

Any Jakarta EE 11 compliant runtime provides the repository implementation with no vendor lock-in.

+
+
+
+ +
+
+
Old Approach
+
JPA EntityManager
+
+
+
Modern Approach
+
Jakarta Data Repository
+
+
+
Since JDK
+
21
+
+
+
Difficulty
+
intermediate
+
+
+ +
+ +
+
JPA versus Jakarta Data
+ Available +

Available since Jakarta EE 11 / Java 21 (2024)

+
+
+ +
+ +

Jakarta Data (Jakarta EE 11) turns data access into a pure interface declaration. You annotate an interface with @Repository and extend a built-in repository type such as CrudRepository. The runtime generates the implementation β€” including derived queries from method names like findByName β€” so there is no EntityManager boilerplate, no JPQL strings, and no hand-written save/find methods.

+
+ +
+ + +
+ + +
+ + + +
+ + + + + +
+ + + + + + \ No newline at end of file