Creating a static site using pure Java. Objectos 0.5.1 released
Tags: java, programming, html, news
Published: 2023-03-20 22:24:44

Welcome to Objectos Weekly issue #018.

I have released Objectos 0.5.1! Most of the work done on this release was internal. In other words, it contains just a few of user-facing changes. I expect the next few releases to follow suit.

In any case, I will show what's new in Objectos 0.5.1.

Let's begin.

## Before we begin

I use Objectos in production. This [very page](https://www.objectos.com.br/blog/objectos-weekly-018-creating-a-static-site-using-pure-java.html) was generated using Objectos HTML (and a few other Objectos libraries).

Having said that, please know that Objectos is alpha software. In particular:

- it is far from being stable: deviate slightly from the shown use-case and it will probably fail;
- API might change substantially between minor/patch releases; and
- documentation is a work in progress.

## Creating a static site using pure Java

The following were introduced to Objectos HTML in version 0.5.1:

- the `HtmlSink` class;
- the `HtmlSink::toDirectory(HtmTemplate, Path)` method;
- the `pathName` instruction of the `HtmlTemplate` class; and
- the `pathTo` instruction of the `HtmlTemplate` class.

They are all related. Let's look at an example to see how they work together.

### Our template

Suppose the following Objectos HTML template:

```java
public class MyTemplate extends HtmlTemplate {
  String pathName;

  @Override
  protected final void definition() {
    pathName(pathName);

    doctype();
    html(
      head(
        title("Objectos HTML example")
      ),
      body(
        p(
          a(pathTo("/index.html"), t("Home"))
        ),
        dl(
          dt("Path name:"),
          dd(pathName)
        )
      )
    );
  }
}
```

Notice the `pathName` instruction at the top of the `definition` method:

```java
@Override
protected final void definition() {
  pathName(pathName);

  ...
}
```

It represents the path of generated HTML file. 

The `pathTo` instruction was used inside the anchor in the template's `body`:

```java
a(pathTo("/index.html"), t("Home"))
```

It is a link that takes you back to the site's home. The `pathTo` instruction generates a `href` attribute. But it uses the `pathName` information to generate a relative link.

### Generating our static site

We will use the `HtmlSink` class to generate our static site to a pre-defined directory.

The following code does that:

```java
var tmpdir = System.getProperty("java.io.tmpdir");

var target = Path.of(tmpdir, "objectos-html-example");

var pathNames = List.of(
  "/index.html",
  "/blog/index.html",
  "/blog/2023/03/17/objectos-html-is-cool.html"
);

var htmlSink = new HtmlSink();

var template = new MyTemplate();

for (var pathName : pathNames) {
  template.pathName = pathName;

  htmlSink.toDirectory(template, target);
}
```

We start by defining our target directory:

```java
var tmpdir = System.getProperty("java.io.tmpdir");

var target = Path.of(tmpdir, "objectos-html-example");
```

I am running Linux, so I expect the target directory to be `/tmp/objectos-html-example`

Next, we define the structure of our static site:

```java
var pathNames = List.of(
  "/index.html",
  "/blog/index.html",
  "/blog/2023/03/17/objectos-html-is-cool.html"
);
```

Note that the pathnames must start with the '/' slash character. Our hypothetical site contains three files. In a real site the structure could come e.g. from your AsciiDoc or Markdown files.

Next, we generate our site using `HtmlSink` and our `MyTemplate` class from before:

```java
var htmlSink = new HtmlSink();

var template = new MyTemplate();

for (var pathName : pathNames) {
  template.pathName = pathName;

  htmlSink.toDirectory(template, target);
}
```

So, for each `pathName` defined, we set the `pathName` instance variable of our template.

Then, we invoke the `HtmlSink::toDirectory` method. Please note that it throws an `IOException`.

### Running our example

After running our example, here's the structure generated:

```
$ find /tmp/objectos-html-example -type f
/tmp/objectos-html-example/blog/2023/03/17/objectos-html-is-cool.html
/tmp/objectos-html-example/blog/index.html
/tmp/objectos-html-example/index.html
```

So the `HtmlSink` class used the `pathName` to generate the directory hierarchy automatically.

Let's look at generate HTML of our home page:

```html
<!doctype html>
<html>
<head>
<title>Objectos HTML example</title>
</head>
<body>
<p><a href="index.html">Home</a></p>
<dl><dt>Path name:</dt><dd>/index.html</dd></dl></body>
</html>
```

Notice the `href` in the anchor: it is not absolute.

The reason becomes clearer in the blog index page:

```html 
<!doctype html>
<html>
<head>
<title>Objectos HTML example</title>
</head>
<body>
<p><a href="../index.html">Home</a></p>
<dl><dt>Path name:</dt><dd>/blog/index.html</dd></dl></body>
</html>
```

Remember we used the `pathTo` instruction in the anchor (instead of a `href`).

The `pathTo` instruction uses the template's `pathName` value to generate a relative link.

For completeness, let's look at the generated HTML of the blog article: 

```html
<!doctype html>
<html>
<head>
<title>Objectos HTML example</title>
</head>
<body>
<p><a href="../../../../index.html">Home</a></p>
<dl><dt>Path name:</dt><dd>/blog/2023/03/17/objectos-html-is-cool.html</dd></dl></body>
</html>
```

So, during development, there's no need for a web server. In other words, you can point your browser to:

```
file:///tmp/html-sink-example/blog/index.html
```

And links should work fine.

## Objectos Code: allow annotations in field declarations

I continue to work on the Objectos Code documentation.

While documenting field declarations I realized that Objectos Code did not allow for fields to be annotated. So I implemented that. And also wrote the [documentation](https://www.objectos.com.br/docs/0.5.1/objectos-code/field/annotations.html) for it.

So the following Objectos Code:

```java
import objectos.code.ClassTypeName;
import objectos.code.JavaTemplate;

public class FieldAnnotations extends JavaTemplate {
  static final ClassTypeName ANNO_A
      = ClassTypeName.of("com.example.annotations", "AnnotationA");
  static final ClassTypeName ANNO_B
      = ClassTypeName.of("com.example.annotations", "AnnotationB");
  static final ClassTypeName ANNO_C
      = ClassTypeName.of("com.example.annotations", "AnnotationC");

  @Override
  protected final void definition() {
    autoImports();

    classDeclaration(
      name("FieldAnnotations"),

      field(
        annotation(ANNO_A),
        annotation(ANNO_B),
        annotation(ANNO_C),
        PUBLIC, INT, name("multiple")
      )
    );
  }
}
```

Generates the following Java code:

```java
import com.example.annotations.AnnotationA;
import com.example.annotations.AnnotationB;
import com.example.annotations.AnnotationC;

class FieldAnnotations {
  @AnnotationA
  @AnnotationB
  @AnnotationC
  public int multiple;
}
```

## Until the next issue of Objectos Weekly

So that's it for today. I hope you enjoyed reading.

The source code of all of the examples are in this [GitHub repository](https://github.com/objectos/blog-examples/tree/master/p038-objectos-0.5.1/src/main/java/post).