Introducing Objectos PetClinic v001! (Part 1)

Marcio EndoMarcio EndoNov 17, 2024

I'm happy to announce the release of Objectos PetClinic v001! Objectos Petclinic is a web application written entirely in Java showcasing:

  • Objectos Way, a library for writing web applications in Java; and

  • Objectos MK, a collection of Makefiles to build Java projects using Make.

This is the first release in a planned series of releases and, while still minimal in functionality, there's already a lot to explore. So much so that I divided this article into two parts.

Let's start.

Objectos PetClinic is inspired by the Spring PetClinic Application.

Write HTML using pure Java

In an Objectos Way web application you write your UI code in pure Java. Here's the Java code that renders the sidebar of the PetClinic:

private Html.Instruction.OfElement sidebar() {  return div(      className("sticky top-0px w-240px h-screen shrink-0 border-r border-r-border px-16px"),      className("body-compact-01"),      div(          className("flex items-center py-20px px-16px"),          raw(UiIcon.LOGO.value),          span(              className("pl-8px"),              text("Objectos PetClinic")          )      ),      nav(          className("pt-16px"),          dataFrame("sidebar", pageSidebar.name()),          renderFragment(this::sidebarItems)      )  );}

It is a regular Java method.

Notice at the bottom, inside the nav tag, the renderFragment method invocation. The argument is a regular Java method reference. Here its implementation:

private void sidebarItems() {  for (UiSidebar item : UiSidebar.VALUES) {    a(        className("flex items-center px-16px py-8px hover:bg-background-hover"),        item == pageSidebar ? className("bg-background-selected") : noop(),        href(item.href),        div(            className("pl-2px"),            raw(item.icon)        ),        div(            className("pl-10px"),            text(item.title)        )    );  }}

It generates the sidebar links based on the values of the UiSidebar enum. Since it is a regular Java method, we can use a for loop:

for (UiSidebar item : UiSidebar.VALUES) {  // render the `a` tag}

And we can use a regular Java expression to conditionally style a link as the currently selected:

item == pageSidebar ? className("bg-background-selected") : noop()

In short, you can use all of the regular Java expressions and statements to define your application UI.

Style using Tailwind-like utility classes

Objectos Way ships with a CSS generator that works similarly to Tailwind CSS. The difference is that it is implemented in pure Java and you configure it using Java code.

The HTML code in the previous section has a number of className invocations of the form:

// an exampleclassName("sticky top-0px w-240px h-screen shrink-0 border-r border-r-border px-16px")// another exampleclassName("flex items-center py-20px px-16px")

The className instruction generates a HTML class attribute. So the following Java code:

div(  className("flex items-center py-20px px-16px"))

Generates the following HTML:

<div class="flex items-center py-20px px-16px"></div>

It also generates the following CSS:

.flex { display: flex }
.items-center { align-items: center }
.px-16px { padding-left: 1rem; padding-right: 1rem }
.py-20px { padding-top: 1.25rem; padding-bottom: 1.25rem }

How the Objectos CSS generator works is beyond the scope of this blog post. In the Objectos PetClinic the generation occurs in a regular HTTP handler:

private void get(Http.Exchange http) {  Css.StyleSheet s;  s = generateStyleSheet();  http.ok(s);}

And you configure the generation using plain Java code. For example, here's how we configure the color values in the PetClinic:

private Css.Option extendColors() {  return Css.extendColors("""  background: var(--ui-background)  background-hover: var(--ui-background-hover)  background-selected: var(--ui-background-selected)  border: var(--ui-border)  text: var(--ui-text)  text-secondary: var(--ui-text-secondary)  """);}

So, apart from the standard color values such as lime-600 and neutral-500, we can use:

div(className("bg-background"))

Which generates the following CSS rule:

.bg-background { background-color: var(--ui-background) }

In short, Objectos Way allows you to create the UI of a web application using pure Java.

Server-Side rendered. Single-page application feel

An Objectos Way application renders all of its pages on the server. But navigation inside the web application does not cause a full-page reload; the developer defines which parts of the DOM will be updated instead. It allows for a smooth and possibly faster transition between pages.

Organize your HTML layout using the data-frame attribute. The Objectos Way JS library will handle the rest for you.

Here's the Java/HTML code of the sidebar of the PetClinic application:

nav(    ...    dataFrame("sidebar", pageSidebar.name()),    ...)

The nav element declares a data-frame attribute. When you are at the home page of the application the nav element is rendered with the following value:

nav(    ...    dataFrame("sidebar", "HOME"),    ...)

And when you are at the owners page of the application, it is rendered with the following:

nav(    ...    dataFrame("sidebar", "OWNERS"),    ...)

We are saying that, when a user navigates from the home page to the owners page (or vice-versa), the browser should replace the nav contents from the old page with the contents of the new page because:

  • the frames have the same name: sidebar; but

  • the values of the frame are different: in one it is HOME and in the other it is OWNERS.

It all happens transparently. In other words, we did not write any Javascript code for it to happen.

Static files are citizens as well

A typical web application needs to serve static files like images, web fonts, Javascript files and so on. Objectos Way provides the Web.Resources facility for this purpose. A Web.Resources instance is mapped to a temporary directory in the server's file system. Here's how the Objectos PetClinic uses it.

First, the application creates an instance of Web.Resources during its bootstrap:

return Web.Resources.create(config -> {  config.noteSink(noteSink);  config.contentTypes("""  .js: text/javascript; charset=utf-8  """);  config.serveFile("/ui/script.js", Script.getBytes());});

The created Web.Resources instance:

  • contains a regular file named script.js in a directory named ui; and

  • will serve any file with the .js file extension with text/javascript; charset=utf-8 as the content-type.

Next, in the application's HTTP module, we create the route:

route("/ui/script.js",    handler(injector.webResources()));

As a result, all requests to the /ui/script.js path will be handled by Web.Resources instance created earlier. The Web.Resources instance will:

  • respond to a GET or HEAD request with either 200 OK or 312 Not Modified; and

  • respond to all other HTTP methods with 405 Method Not Allowed.

Conclusion

Objectos PetClinic v001 should give you an idea on what is like to develop web applications the Objectos Way. Java developers can create web applications without leaving their language of choice.

In part 1 of this series we focused on the features related to the UI creation:

  • write HTML directly in Java allowing you to use regular Java constructs;

  • style your interface using Tailwind-like utility classes;

  • smooth page navigation with the data-frame attribute; and

  • static files are first-class citizens.

In part 2 of this series, we will focus on the development process, SQL utilities and testing.

Check out the project on GitHub.