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.

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay