Create A Full-Stack Java App Using Hilla
Tags: typescript, webdev, beginners, java
Published: 2022-05-16 10:17:56

I've recently come across Hilla, probably on Twitter, and decided to have a play around with it and find out what it does.

This article will serve as an introduction to Hilla.

Let's start.

### What is Hilla?

Hilla is a web framework that uses Java Spring Boot for the backend, Lit library and Typescript for the frontend. 

If you'd like to know more, I wrote an article on my blog about the [Spring Boot Architecture](https://techwithmaddy.com/spring-boot-architecture). 

Spring Boot is a Java backend framework that uses the Spring Framework internally.

Spring Boot makes it easier to bootstrap an application, and it's best used to create [REST APIs](https://techwithmaddy.com/how-to-create-a-spring-boot-rest-api). 

[Lit](https://lit.dev/docs/) library instead 

>  Lit is a simple library for building fast, lightweight web components.
> At Lit's core is a boilerplate-killing component base class that provides reactive state, scoped styles, and a declarative template system that's tiny, fast and expressive.

I'm a backend engineer, so I had to inform myself about the definition of a web component.

According to [webcomponents.org](https://www.webcomponents.org/introduction) :

> Web components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps.

A web component allows you to separate an application into smaller and reusable pieces. 

Typescript is a programming language created and maintained by Microsoft. 

Typescript is:

- strongly-typed.
- supports object-oriented programming.
- supports compilation. 

Hilla allows you to build small and large enterprise-level applications.

Hilla has three main characteristics:

1. **Type-safety**: Hilla makes Java endpoints safe.

2. **UI components**: you won't have to create UI components yourself.

3. **Speed and flexibility**: Hilla uses Lit, a lightweight framework which helps you create components quickly and efficiently. 

You can access Hilla's official documentation [here](https://hilla.dev/).

### 1. ENVIRONMENT SETUP

If you (like me) have never used the Typescript ecosystem, you may have to do a few more installations than the one suggested in Hilla's Documentation.

You will need:

- Node 16.14 or higher.
- Vaadin.
- Lit.
- Typescript.

To install NodeJs, follow the official [page](https://nodejs.org/en/download/).


![nodejs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irbf2c5tbn11sse1lrw0.jpg)

To install the Vaadin CLI (a command-line interface to create Java web applications), run this command in your terminal:


`npm i -g @vaadin/cli`


To install Lit, run this command in your terminal:

`npm i lit`

To install Typescript, run this command in your terminal:

`npm i -g typescript`

### 2. CREATE THE APP VIA THE TERMINAL

To create a Hilla application, run this command in your terminal:

`npx @vaadin/cli init --preset hilla-quickstart-tutorial hilla-student-app`

It may or may not ask you to install `@vaadin/cli`. If so, type `y`.

Import the project into your IDE.

### 3. CREATE THE MODEL CLASS

Let's create a Student.java file under the `src/main/java/com/example/application` directory.

The model class represents a Student object with a name, surname, and age.

```
package com.example.application;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class Student {

    @NotBlank
    private String name;

    @NotBlank
    private String surname;

    @NotNull
    @Min(value = 18)
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
```

### 4. CREATE A STUDENTENDPOINT CLASS

In backend engineering, an "endpoint" typically corresponds to a URL. It's the point that allows communication with another program. 

Hilla guarantees type-safe access to the server.

```
package com.example.application;

import com.vaadin.flow.server.auth.AnonymousAllowed;
import dev.hilla.Endpoint;
import dev.hilla.Nonnull;

import java.util.ArrayList;
import java.util.List;

@Endpoint
@AnonymousAllowed
public class StudentEndpoint {

    private final List<Student> studentList = new ArrayList<>();

    public @Nonnull List<@Nonnull Student> getStudents()    {
        return studentList;
    }

    public Student saveStudent(Student student) {
        studentList.add(student);
        return student;
    }
}
```

Note that the class has two annotations:

- `@endpoint`: this annotation makes the class accessible to the client.
- `@anonymousallowed`: anyone can access this endpoint.  

### 5. CREATE A REACTIVE UI IN TYPESCRIPT

In the  `frontend/views/student/student-view.ts` path, there should be a `studentview.ts` file. If not, create one and paste the following code:

```
import '@vaadin/button';
import '@vaadin/text-field';
import '@vaadin/number-field';
import '@vaadin/grid/vaadin-grid';
import { html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { View } from '../../views/view';
import { Binder, field } from '@hilla/form';
import { getStudents, saveStudent } from 'Frontend/generated/StudentEndpoint';
import Student from 'Frontend/generated/com/example/application/Student';
import StudentModel from 'Frontend/generated/com/example/application/StudentModel';


@customElement('student-view')
export class StudentView extends View {

 @state()
  private students: Student[] = [];
  private binder = new Binder(this, StudentModel);

  render() {
    return html`
          <div class="padding: 25px">
            <div>
              <vaadin-text-field
                ${field(this.binder.model.name)}
                label="Name">
               </vaadin-text-field>
               <vaadin-text-field
               ${field(this.binder.model.surname)}
               label="Surname">
              </vaadin-text-field>
              <vaadin-number-field
                ${field(this.binder.model.age)}
                has-controls
                label="Age">
                </vaadin-number-field>
              <vaadin-button
                theme="primary"
                @click=${this.addStudent}
                ?disabled=${this.binder.invalid}>Add</vaadin-button>
            </div>

            <h3>Student List</h3>
            <vaadin-grid .items="${this.students}" theme="row-stripes" style="max-width: 400px">
              <vaadin-grid-column path="name"></vaadin-grid-column>
              <vaadin-grid-column path="surname"></vaadin-grid-column>
              <vaadin-grid-column path="age"></vaadin-grid-column>
            </vaadin-grid>
          </div>
        `;
  }

      async addStudent() {
        const students = await this.binder.submitTo(saveStudent);
        if (students) {
          this.students = [...this.students, students];
          this.binder.clear();
        }
      }

        async firstUpdated() {
          const students = await getStudents();
          this.students = students;
        }

}
```

Note how this class has a couple of annotations:

- `@customElement`:  this annotation registers the class (student-view) with the browser. 

- `@state`: the students' list is marked with `@state` because it's subject to change.

### 6. RUN THE APPLICATION

Next, run the application.

It should automatically open in the browser, and you should see an app like this:


![student-app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/14pr4eukhhybirkvzf03.jpg)

Add a name, surname, and age.

Then click the `Add` button.


![student-app-added-name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e88gjqs8r2aq43btm4c0.jpg)

Notice that you're not allowed to add a student whose age is under 18:


![student-app-18-not-allowed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibd83pa96imfvf36y9f0.jpg)

When you run the application, you might get something such as:


```
Port XXXX is already in use.
```


To fix this:

- Go into the `resources` folder and open the `application.properties` file.

- Change the `server.port=${PORT:XXXX}` into another port. For example, if the error says that the port 8080 is already in use, change it to 8082 (or 8083, 8585, etc.). 

### CONCLUSION

In this tutorial, you learned how to create a basic Hilla application.

I hope you've found it helpful.

I'm learning Typescript from scratch, so let me know if you've spotted anything incorrect in the comments.

Until next time! 🙋🏾‍♀️

***ADDITIONAL RESOURCES***

- [Hilla Official Documentation](https://hilla.dev/docs/)

- [Lit library](https://lit.dev/)