Skip to main content

Reading J2HTML

J2HTML (j2html) is a Java library used to generate HTML I have been using it to create Web 1.0 applications in Java. Web 1.0 is server-side rendering pages with minimal Javascript.

As I got deeper into using the library I started to read the actual source code of this library with an eye on following Java best practices and to my pleasant surprise, this code follows many of them.


I am going to show here some examples of using interesting Java features, beyond the basics.

1. Functional Interface

People are aware that Java supports some form of Functional Programming, and here is an example of using it:


@FunctionalInterface

public interface Indenter {

    String indent(int level, String text);

}


public static Indenter indenter = (level, text) -> String.join("", Collections.nCopies(level, FOUR_SPACES)) + text;


Things that I noticed:

  • String has a method called join. I used before StringUtils.join, but now that is in the standard library I don’t need to use that anymore

  • Collections has the method nCopies, never used it but clever to have it here

2. Passing Configuration to Inner Methods

Passing configuration to various methods is always complicated because:

  • If we use parameters then there are more and more parameters to pass

  • Or, we use a static class or thread-storage we add configuration but this just hides a dependency. This is called “Ambient Context” anti-pattern.

  • Or we use a property with a reasonable default in classes that need it.


J2HTML uses the third approach. There is a class called Config. This is passed as parameter in the Builder constructor and has a “good” default.


Some ideas from the Config class:

  • All the “good” defaults are exposed as public

  • There is a “defaults” method that returns a Config with the “good” defaults

  • Has a static factory method called global

  • All the operations on config are “copy on write” this avoids concurrency issues

  • The HtmlBuilder gets the config in the constructor and is optional. If not present it gets the defaults.

3. Renderable, Appendable

J2HTML uses several “marker” interfaces.


Renderable is an interface shared by all the Tags, DomContent. Given a builder it will return a string.


public interface Renderable {

    default <T extends Appendable> T render(HtmlBuilder<T> builder, Object model) throws  IOException;

}


There are a few assumptions in this interface:

  • All the builders will be HTML builders

  • The parameter of the render method is the output type which is appendable (e.g. StringBuilder, StringWriter)


4. Recursive Type Bound

In a few places I see a parameterized class definitions like these:

public abstract class Tag<T extends Tag<T>> extends DomContent  {

  …

}


public class ContainerTag<T extends ContainerTag<T>> extends Tag<T> {

   …

}


public class PTag extends ContainerTag<PTag> {

  public PTag() {

    super("p");

  }

}


These kinds of definitions are useful to implement fluent APIs that are at the same time typesafe. Another advantage is that the autocomplete will show only the appropriate methods.


A good explanation of why this is useful is in this Stack Overflow article: https://stackoverflow.com/questions/7385949/what-does-recursive-type-bound-in-generics-mean


5. No Components

While j2html has many useful and interesting abstractions, it does not have a component model or abstractions to convert business objectives into HTML code. This has to be done by the application developer.


Popular posts from this blog

View - A Functor for Web App Design

This blog is about practical applications of Category Theory to the development of Java + Spring applications. I am looking at a design approach to simplify the development of web applications. Traditionally, this kind of back-office application is based on the Web 1.0 technology stack, using Spring Boot and Thymeleaf. My approach is to keep using Spring Boot but replace the generation of HTML with J2HTML and higher-order views. From a Category Theory point of view, we can look at web applications as mappings from the Category of Business Entities and the Category of UI Widgets. If we go one step further, both business entities and UI widgets are mapped to Java classes. Thus, we can view a web application (or a part of it) as an endofunctor in the Category of Java Classes. We define the View-functor as follows: domain(V) - Java classes representing business entities - e.g., Invoice, User - and, codomain(V) - Java functions that render the business entity as a DomContent object (DomCont...

Web Application Development following Functional Programming Principles

After studying category theory and functional programming, I decided to put these concepts into practice by developing a simple web application. This project was inspired by the example in Chapter 11 of 'Programming in Haskell' by Graham Hutton. My goal was to take these theoretical programming ideas and see how they work in creating a real-world web application. The key concepts of functional programming are: Prioritize creating pure functions as much as possible. These are functions without side effects, making them simpler to test Use composition of pure functions to construct more intricate functions Use Functors, Applicatives, and Monads in scenarios that require pure functions, such as error handling or managing missing values, and when working with collections like trees and lists. I wrote this application in Java, utilizing the Spring Boot framework. This decision was influenced by my previous work in developing enterprise applications with this technology stack. My obj...