diff --git a/.gitignore b/.gitignore index d0ce4ae..0658df9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ site/errors/*.html site/datetime/*.html site/security/*.html site/tooling/*.html +site/enterprise/*.html # Generated aggregate file (built from individual JSON sources by html-generators/) site/data/snippets.json diff --git a/html-generators/categories.properties b/html-generators/categories.properties new file mode 100644 index 0000000..2093258 --- /dev/null +++ b/html-generators/categories.properties @@ -0,0 +1,11 @@ +language=Language +collections=Collections +strings=Strings +streams=Streams +concurrency=Concurrency +io=I/O +errors=Errors +datetime=Date/Time +security=Security +tooling=Tooling +enterprise=Enterprise diff --git a/html-generators/generate.java b/html-generators/generate.java index 0a9c244..f927f1a 100644 --- a/html-generators/generate.java +++ b/html-generators/generate.java @@ -16,13 +16,23 @@ static final Pattern TOKEN = Pattern.compile("\\{\\{(\\w+)}}"); static final ObjectMapper MAPPER = new ObjectMapper(); -static final SequencedMap CATEGORY_DISPLAY = new LinkedHashMap<>() {{ - put("language", "Language"); put("collections", "Collections"); - put("strings", "Strings"); put("streams", "Streams"); - put("concurrency", "Concurrency"); put("io", "I/O"); - put("errors", "Errors"); put("datetime", "Date/Time"); - put("security", "Security"); put("tooling", "Tooling"); -}}; +static final String CATEGORIES_FILE = "html-generators/categories.properties"; +static final SequencedMap CATEGORY_DISPLAY = loadCategoryDisplay(); + +static SequencedMap loadCategoryDisplay() { + try { + var map = new LinkedHashMap(); + for (var line : Files.readAllLines(Path.of(CATEGORIES_FILE))) { + line = line.strip(); + if (line.isEmpty() || line.startsWith("#")) continue; + var idx = line.indexOf('='); + if (idx > 0) map.put(line.substring(0, idx).strip(), line.substring(idx + 1).strip()); + } + return map; + } catch (IOException e) { + throw new UncheckedIOException(e); + } +} static final Set EXCLUDED_KEYS = Set.of("_path", "prev", "next", "related"); diff --git a/html-generators/generate.py b/html-generators/generate.py index fcf6f5a..b9f2739 100644 --- a/html-generators/generate.py +++ b/html-generators/generate.py @@ -19,19 +19,25 @@ CONTENT_DIR = "content" SITE_DIR = "site" -CATEGORY_DISPLAY = { - "language": "Language", - "collections": "Collections", - "strings": "Strings", - "streams": "Streams", - "concurrency": "Concurrency", - "io": "I/O", - "errors": "Errors", - "datetime": "Date/Time", - "security": "Security", - "tooling": "Tooling", - "enterprise": "Enterprise", -} +CATEGORIES_FILE = "html-generators/categories.properties" + + +def load_category_display(): + """Load category display names from the properties file.""" + categories = {} + with open(CATEGORIES_FILE) as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + key, sep, value = line.partition('=') + key, value = key.strip(), value.strip() + if sep and key: + categories[key] = value + return categories + + +CATEGORY_DISPLAY = load_category_display() def escape(text): @@ -65,12 +71,8 @@ def load_template(): def load_all_snippets(): """Load all JSON snippet files, keyed by category/slug.""" snippets = {} - categories = [ - "language", "collections", "strings", "streams", "concurrency", - "io", "errors", "datetime", "security", "tooling", "enterprise", - ] json_files = [] - for cat in categories: + for cat in CATEGORY_DISPLAY: json_files.extend(sorted(glob.glob(f"{CONTENT_DIR}/{cat}/*.json"))) for path in json_files: with open(path) as f: diff --git a/site/enterprise/ejb-vs-cdi.html b/site/enterprise/ejb-vs-cdi.html deleted file mode 100644 index 288e8d5..0000000 --- a/site/enterprise/ejb-vs-cdi.html +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - 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 deleted file mode 100644 index 1d05576..0000000 --- a/site/enterprise/jdbc-vs-jpa.html +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - 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/jpa-vs-jakarta-data.html b/site/enterprise/jpa-vs-jakarta-data.html deleted file mode 100644 index 77110a4..0000000 --- a/site/enterprise/jpa-vs-jakarta-data.html +++ /dev/null @@ -1,397 +0,0 @@ - - - - - - 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 diff --git a/site/enterprise/servlet-vs-jaxrs.html b/site/enterprise/servlet-vs-jaxrs.html deleted file mode 100644 index 0522865..0000000 --- a/site/enterprise/servlet-vs-jaxrs.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - 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