DEV Community

Cover image for Creating a static site using pure Java. Objectos 0.5.1 released
Marcio Endo
Marcio Endo

Posted on • Originally published at objectos.com.br

Creating a static site using pure Java. Objectos 0.5.1 released

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 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:

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)
        )
      )
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

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

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

  ...
}
Enter fullscreen mode Exit fullscreen mode

It represents the path of generated HTML file.

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

a(pathTo("/index.html"), t("Home"))
Enter fullscreen mode Exit fullscreen mode

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:

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);
}
Enter fullscreen mode Exit fullscreen mode

We start by defining our target directory:

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

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

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:

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

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:

var htmlSink = new HtmlSink();

var template = new MyTemplate();

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

  htmlSink.toDirectory(template, target);
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

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

<!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>
Enter fullscreen mode Exit fullscreen mode

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

The reason becomes clearer in the blog index page:

<!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>
Enter fullscreen mode Exit fullscreen mode

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:

<!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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 for it.

So the following Objectos Code:

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")
      )
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Generates the following Java code:

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

class FieldAnnotations {
  @AnnotationA
  @AnnotationB
  @AnnotationC
  public int multiple;
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)