From 831bdaf93711f577c6dd766b585ce4f9e0c0137d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:17:54 +0000 Subject: [PATCH 1/2] Initial plan From cff2ea64bd0e8fff75a975e5ba623d2b988157e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:23:09 +0000 Subject: [PATCH 2/2] Add 8 new enterprise category patterns from issue #45 ideas Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com> --- .../ejb-timer-vs-jakarta-scheduler.json | 54 +++++++++++++++++++ .../jdbc-resultset-vs-jpa-criteria.json | 54 +++++++++++++++++++ .../jndi-lookup-vs-cdi-injection.json | 54 +++++++++++++++++++ content/enterprise/jpa-vs-jakarta-data.json | 2 +- .../jsf-managed-bean-vs-cdi-named.json | 54 +++++++++++++++++++ .../manual-transaction-vs-declarative.json | 54 +++++++++++++++++++ .../enterprise/mdb-vs-reactive-messaging.json | 54 +++++++++++++++++++ ...ngleton-ejb-vs-cdi-application-scoped.json | 54 +++++++++++++++++++ content/enterprise/soap-vs-jakarta-rest.json | 54 +++++++++++++++++++ 9 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 content/enterprise/ejb-timer-vs-jakarta-scheduler.json create mode 100644 content/enterprise/jdbc-resultset-vs-jpa-criteria.json create mode 100644 content/enterprise/jndi-lookup-vs-cdi-injection.json create mode 100644 content/enterprise/jsf-managed-bean-vs-cdi-named.json create mode 100644 content/enterprise/manual-transaction-vs-declarative.json create mode 100644 content/enterprise/mdb-vs-reactive-messaging.json create mode 100644 content/enterprise/singleton-ejb-vs-cdi-application-scoped.json create mode 100644 content/enterprise/soap-vs-jakarta-rest.json diff --git a/content/enterprise/ejb-timer-vs-jakarta-scheduler.json b/content/enterprise/ejb-timer-vs-jakarta-scheduler.json new file mode 100644 index 0000000..52f8d07 --- /dev/null +++ b/content/enterprise/ejb-timer-vs-jakarta-scheduler.json @@ -0,0 +1,54 @@ +{ + "id": 102, + "slug": "ejb-timer-vs-jakarta-scheduler", + "title": "EJB Timer vs Jakarta Scheduler", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 10+", + "oldApproach": "EJB TimerService", + "modernApproach": "ManagedScheduledExecutorService", + "oldCode": "@Stateless\npublic class ReportGenerator {\n @Resource\n TimerService timerService;\n\n @PostConstruct\n public void init() {\n timerService.createCalendarTimer(\n new ScheduleExpression()\n .hour(\"2\").minute(\"0\"));\n }\n\n @Timeout\n public void generateReport(Timer timer) {\n // runs every day at 02:00\n buildDailyReport();\n }\n}", + "modernCode": "@ApplicationScoped\npublic class ReportGenerator {\n @Resource\n ManagedScheduledExecutorService scheduler;\n\n @PostConstruct\n public void init() {\n scheduler.scheduleAtFixedRate(\n this::generateReport,\n 0, 24, TimeUnit.HOURS);\n }\n\n public void generateReport() {\n buildDailyReport();\n }\n}", + "summary": "Replace heavyweight EJB timers with Jakarta Concurrency's ManagedScheduledExecutorService for simpler scheduling.", + "explanation": "EJB timers require a @Stateless or @Singleton bean with a @Timeout callback and XML or annotation-based schedule expressions. Jakarta Concurrency provides ManagedScheduledExecutorService, which uses the familiar java.util.concurrent scheduling API. The result is less boilerplate, easier unit testing, and no EJB container dependency.", + "whyModernWins": [ + { + "icon": "๐Ÿชถ", + "title": "Reduced boilerplate", + "desc": "No @Timeout callback or ScheduleExpression โ€” use the standard ScheduledExecutorService API." + }, + { + "icon": "๐Ÿงช", + "title": "Better testability", + "desc": "Plain methods and executor mocks make unit testing straightforward without EJB container." + }, + { + "icon": "โ˜๏ธ", + "title": "Cloud-native friendly", + "desc": "Managed executors integrate with container lifecycle and work in lightweight runtimes." + } + ], + "support": { + "state": "available", + "description": "Available since Jakarta EE 10 / Concurrency 3.0" + }, + "prev": "enterprise/jpa-vs-jakarta-data", + "next": "enterprise/jndi-lookup-vs-cdi-injection", + "related": [ + "enterprise/ejb-vs-cdi", + "concurrency/virtual-threads", + "concurrency/executor-try-with-resources" + ], + "docs": [ + { + "title": "Jakarta Concurrency Specification", + "href": "https://jakarta.ee/specifications/concurrency/" + }, + { + "title": "Jakarta Concurrency 3.0 API", + "href": "https://jakarta.ee/specifications/concurrency/3.0/apidocs/" + } + ] +} diff --git a/content/enterprise/jdbc-resultset-vs-jpa-criteria.json b/content/enterprise/jdbc-resultset-vs-jpa-criteria.json new file mode 100644 index 0000000..c35abf9 --- /dev/null +++ b/content/enterprise/jdbc-resultset-vs-jpa-criteria.json @@ -0,0 +1,54 @@ +{ + "id": 109, + "slug": "jdbc-resultset-vs-jpa-criteria", + "title": "JDBC ResultSet Mapping vs JPA Criteria API", + "category": "enterprise", + "difficulty": "advanced", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "JDBC ResultSet", + "modernApproach": "JPA Criteria API", + "oldCode": "String sql = \"SELECT * FROM users\"\n + \" WHERE status = ? AND age > ?\";\ntry (Connection con = ds.getConnection();\n PreparedStatement ps =\n con.prepareStatement(sql)) {\n ps.setString(1, status);\n ps.setInt(2, minAge);\n ResultSet rs = ps.executeQuery();\n List users = new ArrayList<>();\n while (rs.next()) {\n User u = new User();\n u.setId(rs.getLong(\"id\"));\n u.setName(rs.getString(\"name\"));\n u.setAge(rs.getInt(\"age\"));\n users.add(u);\n }\n}", + "modernCode": "@PersistenceContext\nEntityManager em;\n\npublic List findActiveAboveAge(\n String status, int minAge) {\n CriteriaBuilder cb = em.getCriteriaBuilder();\n CriteriaQuery cq =\n cb.createQuery(User.class);\n Root root = cq.from(User.class);\n cq.select(root).where(\n cb.equal(root.get(\"status\"), status),\n cb.greaterThan(root.get(\"age\"), minAge));\n return em.createQuery(cq).getResultList();\n}", + "summary": "Replace manual JDBC ResultSet mapping with JPA's type-safe Criteria API for dynamic queries.", + "explanation": "Raw JDBC requires building SQL strings, setting parameters by index, and mapping each ResultSet column manually โ€” a process that is error-prone and breaks silently when columns change. The JPA Criteria API builds queries programmatically using a type-safe builder pattern. Column names are validated against the entity model, result mapping is automatic, and complex dynamic queries compose cleanly without string concatenation.", + "whyModernWins": [ + { + "icon": "๐Ÿ”’", + "title": "Type-safe queries", + "desc": "The Criteria builder catches field name and type mismatches at compile time." + }, + { + "icon": "๐Ÿ—บ๏ธ", + "title": "Automatic mapping", + "desc": "JPA maps result rows to entity objects โ€” no manual column-by-column extraction." + }, + { + "icon": "๐Ÿงฉ", + "title": "Composable predicates", + "desc": "Dynamic where-clauses build cleanly with and(), or(), and reusable Predicate objects." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/singleton-ejb-vs-cdi-application-scoped", + "next": null, + "related": [ + "enterprise/jdbc-vs-jpa", + "enterprise/jpa-vs-jakarta-data", + "enterprise/manual-transaction-vs-declarative" + ], + "docs": [ + { + "title": "Jakarta Persistence Specification", + "href": "https://jakarta.ee/specifications/persistence/" + }, + { + "title": "Jakarta Persistence 3.1 โ€” Criteria API", + "href": "https://jakarta.ee/specifications/persistence/3.1/apidocs/" + } + ] +} diff --git a/content/enterprise/jndi-lookup-vs-cdi-injection.json b/content/enterprise/jndi-lookup-vs-cdi-injection.json new file mode 100644 index 0000000..c29e9dc --- /dev/null +++ b/content/enterprise/jndi-lookup-vs-cdi-injection.json @@ -0,0 +1,54 @@ +{ + "id": 103, + "slug": "jndi-lookup-vs-cdi-injection", + "title": "JNDI Lookup vs CDI Injection", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "JNDI Lookup", + "modernApproach": "CDI @Inject", + "oldCode": "public class OrderService {\n private DataSource ds;\n\n public void init() throws NamingException {\n InitialContext ctx = new InitialContext();\n ds = (DataSource) ctx.lookup(\n \"java:comp/env/jdbc/OrderDB\");\n }\n\n public List findAll()\n throws SQLException {\n try (Connection con = ds.getConnection()) {\n // query orders\n }\n }\n}", + "modernCode": "@ApplicationScoped\npublic class OrderService {\n @Inject\n @Resource(name = \"jdbc/OrderDB\")\n DataSource ds;\n\n public List findAll()\n throws SQLException {\n try (Connection con = ds.getConnection()) {\n // query orders\n }\n }\n}", + "summary": "Replace fragile JNDI string lookups with type-safe CDI injection for container-managed resources.", + "explanation": "The traditional JNDI pattern forces you to use string-based resource names, handle NamingException, and manage an InitialContext. CDI injection with @Inject (or @Resource for container resources) lets the container wire dependencies automatically. Typos become compile-time errors, and classes are easier to test because dependencies can be injected directly.", + "whyModernWins": [ + { + "icon": "๐Ÿ”’", + "title": "Type-safe wiring", + "desc": "Injection errors are caught at deployment time, not at runtime via string lookups." + }, + { + "icon": "๐Ÿ—‘๏ธ", + "title": "No boilerplate", + "desc": "Eliminates InitialContext creation, JNDI name strings, and NamingException handling." + }, + { + "icon": "๐Ÿงช", + "title": "Testable", + "desc": "Dependencies are injected fields, easily replaced with mocks in unit tests." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/ejb-timer-vs-jakarta-scheduler", + "next": "enterprise/manual-transaction-vs-declarative", + "related": [ + "enterprise/ejb-vs-cdi", + "enterprise/jdbc-vs-jpa", + "enterprise/singleton-ejb-vs-cdi-application-scoped" + ], + "docs": [ + { + "title": "Jakarta CDI Specification", + "href": "https://jakarta.ee/specifications/cdi/" + }, + { + "title": "Jakarta Annotations โ€” @Resource", + "href": "https://jakarta.ee/specifications/annotations/" + } + ] +} diff --git a/content/enterprise/jpa-vs-jakarta-data.json b/content/enterprise/jpa-vs-jakarta-data.json index a5a8ef2..2d82e1a 100644 --- a/content/enterprise/jpa-vs-jakarta-data.json +++ b/content/enterprise/jpa-vs-jakarta-data.json @@ -35,7 +35,7 @@ "description": "Available since Jakarta EE 11 / Java 21 (2024)" }, "prev": "enterprise/jdbc-vs-jpa", - "next": null, + "next": "enterprise/ejb-timer-vs-jakarta-scheduler", "related": [ "enterprise/jdbc-vs-jpa", "enterprise/ejb-vs-cdi", diff --git a/content/enterprise/jsf-managed-bean-vs-cdi-named.json b/content/enterprise/jsf-managed-bean-vs-cdi-named.json new file mode 100644 index 0000000..a9468a2 --- /dev/null +++ b/content/enterprise/jsf-managed-bean-vs-cdi-named.json @@ -0,0 +1,54 @@ +{ + "id": 107, + "slug": "jsf-managed-bean-vs-cdi-named", + "title": "JSF Managed Bean vs CDI Named Bean", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 10+", + "oldApproach": "@ManagedBean", + "modernApproach": "@Named + CDI", + "oldCode": "@ManagedBean\n@SessionScoped\npublic class UserBean implements Serializable {\n @ManagedProperty(\"#{userService}\")\n private UserService userService;\n\n private String name;\n\n public String getName() { return name; }\n public void setName(String name) {\n this.name = name;\n }\n\n public void setUserService(UserService svc) {\n this.userService = svc;\n }\n}", + "modernCode": "@Named\n@SessionScoped\npublic class UserBean implements Serializable {\n @Inject\n private UserService userService;\n\n private String name;\n\n public String getName() { return name; }\n public void setName(String name) {\n this.name = name;\n }\n}", + "summary": "Replace deprecated JSF @ManagedBean with CDI @Named for a unified dependency injection model.", + "explanation": "JSF's @ManagedBean and @ManagedProperty were deprecated in Jakarta Faces 2.3 and removed in Jakarta EE 10. The CDI-based replacement uses @Named to expose the bean to EL expressions and @Inject for dependency wiring. This unifies the bean model: JSF pages, JAX-RS resources, and EJBs all share the same CDI container.", + "whyModernWins": [ + { + "icon": "๐Ÿ”—", + "title": "Unified model", + "desc": "One CDI container manages all beans โ€” JSF, REST, and service layers share the same injection." + }, + { + "icon": "๐Ÿ—‘๏ธ", + "title": "Less boilerplate", + "desc": "@Inject replaces @ManagedProperty and its required setter method." + }, + { + "icon": "๐Ÿ”ฎ", + "title": "Future-proof", + "desc": "@ManagedBean is removed in Jakarta EE 10; @Named is the supported replacement." + } + ], + "support": { + "state": "available", + "description": "CDI @Named available since Java EE 6; @ManagedBean removed in Jakarta EE 10" + }, + "prev": "enterprise/mdb-vs-reactive-messaging", + "next": "enterprise/singleton-ejb-vs-cdi-application-scoped", + "related": [ + "enterprise/ejb-vs-cdi", + "enterprise/jndi-lookup-vs-cdi-injection", + "enterprise/servlet-vs-jaxrs" + ], + "docs": [ + { + "title": "Jakarta Faces Specification", + "href": "https://jakarta.ee/specifications/faces/" + }, + { + "title": "Jakarta CDI Specification", + "href": "https://jakarta.ee/specifications/cdi/" + } + ] +} diff --git a/content/enterprise/manual-transaction-vs-declarative.json b/content/enterprise/manual-transaction-vs-declarative.json new file mode 100644 index 0000000..31e2417 --- /dev/null +++ b/content/enterprise/manual-transaction-vs-declarative.json @@ -0,0 +1,54 @@ +{ + "id": 104, + "slug": "manual-transaction-vs-declarative", + "title": "Manual JPA Transaction vs Declarative @Transactional", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "Manual Transaction", + "modernApproach": "@Transactional", + "oldCode": "@PersistenceContext\nEntityManager em;\n\npublic void transferFunds(Long from, Long to,\n BigDecimal amount) {\n EntityTransaction tx = em.getTransaction();\n tx.begin();\n try {\n Account src = em.find(Account.class, from);\n Account dst = em.find(Account.class, to);\n src.debit(amount);\n dst.credit(amount);\n tx.commit();\n } catch (Exception e) {\n tx.rollback();\n throw e;\n }\n}", + "modernCode": "@ApplicationScoped\npublic class AccountService {\n @PersistenceContext\n EntityManager em;\n\n @Transactional\n public void transferFunds(Long from, Long to,\n BigDecimal amount) {\n Account src = em.find(Account.class, from);\n Account dst = em.find(Account.class, to);\n src.debit(amount);\n dst.credit(amount);\n }\n}", + "summary": "Replace verbose begin/commit/rollback blocks with a single @Transactional annotation.", + "explanation": "Manual transaction management requires explicit begin(), commit(), and rollback() calls wrapped in try-catch blocks โ€” every service method repeats this boilerplate. The @Transactional annotation delegates lifecycle management to the container: it begins a transaction before the method, commits on success, and rolls back on RuntimeException automatically.", + "whyModernWins": [ + { + "icon": "๐Ÿ—‘๏ธ", + "title": "No boilerplate", + "desc": "One annotation replaces repetitive begin/commit/rollback try-catch blocks." + }, + { + "icon": "๐Ÿ›ก๏ธ", + "title": "Safer rollback", + "desc": "The container guarantees rollback on unchecked exceptions โ€” no risk of forgetting the catch block." + }, + { + "icon": "๐Ÿ“", + "title": "Declarative control", + "desc": "Propagation, isolation, and rollback rules are expressed as annotation attributes." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/jndi-lookup-vs-cdi-injection", + "next": "enterprise/soap-vs-jakarta-rest", + "related": [ + "enterprise/ejb-vs-cdi", + "enterprise/jdbc-vs-jpa", + "enterprise/jpa-vs-jakarta-data" + ], + "docs": [ + { + "title": "Jakarta Transactions Specification", + "href": "https://jakarta.ee/specifications/transactions/" + }, + { + "title": "Jakarta Transactions 2.0 API", + "href": "https://jakarta.ee/specifications/transactions/2.0/apidocs/" + } + ] +} diff --git a/content/enterprise/mdb-vs-reactive-messaging.json b/content/enterprise/mdb-vs-reactive-messaging.json new file mode 100644 index 0000000..4d87ef7 --- /dev/null +++ b/content/enterprise/mdb-vs-reactive-messaging.json @@ -0,0 +1,54 @@ +{ + "id": 106, + "slug": "mdb-vs-reactive-messaging", + "title": "Message-Driven Bean vs Reactive Messaging", + "category": "enterprise", + "difficulty": "advanced", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "MicroProfile 4+", + "oldApproach": "Message-Driven Bean", + "modernApproach": "Reactive Messaging", + "oldCode": "@MessageDriven(activationConfig = {\n @ActivationConfigProperty(\n propertyName = \"destinationType\",\n propertyValue = \"jakarta.jms.Queue\"),\n @ActivationConfigProperty(\n propertyName = \"destination\",\n propertyValue = \"java:/jms/OrderQueue\")\n})\npublic class OrderMDB implements MessageListener {\n @Override\n public void onMessage(Message message) {\n TextMessage txt = (TextMessage) message;\n processOrder(txt.getText());\n }\n}", + "modernCode": "@ApplicationScoped\npublic class OrderProcessor {\n @Incoming(\"orders\")\n public void process(Order order) {\n // automatically deserialized from\n // the \"orders\" channel\n fulfillOrder(order);\n }\n}", + "summary": "Replace JMS Message-Driven Beans with MicroProfile Reactive Messaging for simpler event processing.", + "explanation": "Message-Driven Beans require implementing MessageListener, configuring activation properties, and manually deserializing JMS messages. MicroProfile Reactive Messaging uses a simple @Incoming annotation on a method that receives typed objects directly. The channel configuration is externalised, making the code broker-agnostic and far easier to test.", + "whyModernWins": [ + { + "icon": "๐Ÿชถ", + "title": "Minimal code", + "desc": "A single @Incoming method replaces the MDB class, MessageListener interface, and activation config." + }, + { + "icon": "๐Ÿ”Œ", + "title": "Broker-agnostic", + "desc": "Swap Kafka, AMQP, or JMS connectors via configuration without changing application code." + }, + { + "icon": "โ˜๏ธ", + "title": "Cloud-native fit", + "desc": "Reactive streams backpressure and lightweight runtime make it ideal for containerised deployments." + } + ], + "support": { + "state": "available", + "description": "Available since MicroProfile 4.0 / SmallRye Reactive Messaging" + }, + "prev": "enterprise/soap-vs-jakarta-rest", + "next": "enterprise/jsf-managed-bean-vs-cdi-named", + "related": [ + "enterprise/ejb-vs-cdi", + "concurrency/structured-concurrency", + "concurrency/virtual-threads" + ], + "docs": [ + { + "title": "MicroProfile Reactive Messaging Specification", + "href": "https://download.eclipse.org/microprofile/microprofile-reactive-messaging-3.0/microprofile-reactive-messaging-spec-3.0.html" + }, + { + "title": "SmallRye Reactive Messaging Documentation", + "href": "https://smallrye.io/smallrye-reactive-messaging/" + } + ] +} diff --git a/content/enterprise/singleton-ejb-vs-cdi-application-scoped.json b/content/enterprise/singleton-ejb-vs-cdi-application-scoped.json new file mode 100644 index 0000000..fa5df0c --- /dev/null +++ b/content/enterprise/singleton-ejb-vs-cdi-application-scoped.json @@ -0,0 +1,54 @@ +{ + "id": 108, + "slug": "singleton-ejb-vs-cdi-application-scoped", + "title": "Singleton EJB vs CDI @ApplicationScoped", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "@Singleton EJB", + "modernApproach": "@ApplicationScoped CDI", + "oldCode": "@Singleton\n@Startup\n@ConcurrencyManagement(\n ConcurrencyManagementType.CONTAINER)\npublic class ConfigCache {\n private Map cache;\n\n @PostConstruct\n public void load() {\n cache = loadFromDatabase();\n }\n\n @Lock(LockType.READ)\n public String get(String key) {\n return cache.get(key);\n }\n\n @Lock(LockType.WRITE)\n public void refresh() {\n cache = loadFromDatabase();\n }\n}", + "modernCode": "@ApplicationScoped\npublic class ConfigCache {\n private volatile Map cache;\n\n @PostConstruct\n public void load() {\n cache = loadFromDatabase();\n }\n\n public String get(String key) {\n return cache.get(key);\n }\n\n public void refresh() {\n cache = loadFromDatabase();\n }\n}", + "summary": "Replace Singleton EJBs with CDI @ApplicationScoped beans for simpler shared-state management.", + "explanation": "Singleton EJBs bundle concurrency management (@Lock, @ConcurrencyManagement) and eager initialisation (@Startup) into the EJB container. A CDI @ApplicationScoped bean achieves the same single-instance lifecycle with far less ceremony. When concurrency control is needed, standard java.util.concurrent utilities give you finer-grained control than the EJB lock annotations.", + "whyModernWins": [ + { + "icon": "๐Ÿชถ", + "title": "Less annotation noise", + "desc": "No @ConcurrencyManagement, @Lock, or @Startup โ€” just a single @ApplicationScoped annotation." + }, + { + "icon": "๐Ÿ”ง", + "title": "Flexible concurrency", + "desc": "Use java.util.concurrent locks or volatile for exactly the thread-safety you need." + }, + { + "icon": "๐Ÿงช", + "title": "Easy testing", + "desc": "Plain CDI beans can be instantiated directly in tests without an EJB container." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/jsf-managed-bean-vs-cdi-named", + "next": "enterprise/jdbc-resultset-vs-jpa-criteria", + "related": [ + "enterprise/ejb-vs-cdi", + "enterprise/jndi-lookup-vs-cdi-injection", + "concurrency/lock-free-lazy-init" + ], + "docs": [ + { + "title": "Jakarta CDI Specification", + "href": "https://jakarta.ee/specifications/cdi/" + }, + { + "title": "Jakarta Enterprise Beans Specification", + "href": "https://jakarta.ee/specifications/enterprise-beans/" + } + ] +} diff --git a/content/enterprise/soap-vs-jakarta-rest.json b/content/enterprise/soap-vs-jakarta-rest.json new file mode 100644 index 0000000..2d42299 --- /dev/null +++ b/content/enterprise/soap-vs-jakarta-rest.json @@ -0,0 +1,54 @@ +{ + "id": 105, + "slug": "soap-vs-jakarta-rest", + "title": "SOAP Web Services vs Jakarta REST", + "category": "enterprise", + "difficulty": "intermediate", + "jdkVersion": "11", + "oldLabel": "Java EE", + "modernLabel": "Jakarta EE 8+", + "oldApproach": "JAX-WS / SOAP", + "modernApproach": "Jakarta REST / JSON", + "oldCode": "@WebService\npublic class UserWebService {\n @WebMethod\n public UserResponse getUser(\n @WebParam(name = \"id\") String id) {\n User user = findUser(id);\n UserResponse res = new UserResponse();\n res.setId(user.getId());\n res.setName(user.getName());\n return res;\n }\n}", + "modernCode": "@Path(\"/users\")\n@Produces(MediaType.APPLICATION_JSON)\npublic class UserResource {\n @Inject\n UserService userService;\n\n @GET\n @Path(\"/{id}\")\n public User getUser(@PathParam(\"id\") String id) {\n return userService.findById(id);\n }\n}", + "summary": "Replace heavyweight SOAP/WSDL endpoints with clean Jakarta REST resources returning JSON.", + "explanation": "SOAP-based web services rely on WSDL contracts, XML marshalling, and JAX-WS annotations that add significant overhead. Jakarta REST (formerly JAX-RS) uses intuitive annotations like @GET, @Path, and @Produces to expose RESTful JSON APIs. The programming model is simpler, the payloads are smaller, and the approach aligns with how modern microservices communicate.", + "whyModernWins": [ + { + "icon": "๐Ÿชถ", + "title": "Lighter payloads", + "desc": "JSON is more compact than SOAP XML envelopes, reducing bandwidth and parsing overhead." + }, + { + "icon": "๐Ÿ“", + "title": "Simple annotations", + "desc": "@GET, @Path, and @Produces replace WSDL, @WebService, and @WebMethod ceremony." + }, + { + "icon": "๐Ÿ”Œ", + "title": "Microservice-ready", + "desc": "REST/JSON is the standard for service-to-service communication in cloud-native architectures." + } + ], + "support": { + "state": "available", + "description": "Widely available since Jakarta EE 8 / Java 11" + }, + "prev": "enterprise/manual-transaction-vs-declarative", + "next": "enterprise/mdb-vs-reactive-messaging", + "related": [ + "enterprise/servlet-vs-jaxrs", + "io/http-client", + "enterprise/ejb-vs-cdi" + ], + "docs": [ + { + "title": "Jakarta RESTful Web Services Specification", + "href": "https://jakarta.ee/specifications/restful-ws/" + }, + { + "title": "Jakarta JSON Binding Specification", + "href": "https://jakarta.ee/specifications/jsonb/" + } + ] +}