Learning to use Micronaut Framework to develop a software pet project

Software engineers who worked extensively with Java technology might have come across and/or use Spring Framework for their projects (professional or personal). In 2013, the Spring Boot project was started to simplify the deployment of spring-based web application.

Personally, I have used it at the beginning of my programming career back in 2015 after being introduced to it by my supervisor/senior. Before that, I have used JSP/Servlet for my school projects that are for the web and Java Swing for desktop-based applications. I was also exposed to working with EJB as part of my diploma course back in 2006/2007. Through all that, I became aware of how fast Spring Boot is and the whole Spring Framework allowed me to be more productive. Annotations were the sliver bullet for me then.

And I had plans to use Spring Boot again for my pet projects since it was something familiar…

Some Background

One of my pet projects was to build a public transport dashboard that could tell me when are the buses for specific bus stops arriving, and if I missed them, how long more do I have to wait for them.

Yes, I know there are apps that I could use on my phone but they are cumbersome. Face mask is also a requirement in Singapore that made it difficult to unlock my phone in a split second…yes I’m impatient.

So, here are my requirements:

  1. I’m only interested in four specific bus stops that are around my apartment block and four specific bus services.
  2. I want the information displayed near my apartment’s main door in a succinct manner.
  3. I don’t want to unlock my phone, open the public transport app and look for the buses.
  4. The app will display the information with live updates every minute.
  5. The tablet/computer running the app will always put it on the foreground for instant access.

What have I done so far?

With the requirements in hand, I went about building a web app that could run on a Raspberry Pi with a touchscreen display.

For the frontend, I went with Angular and it does not matter which version. The goal was just for me to learn how to setup a new Angular project and build something functional with it. The only other time I used Angular was on an actual project but I wasn’t the one who set it up. I simply continued developing on it.

I spend a few hours to get started with Angular and finding my way around. I was developing the app as I learnt.

Here is the prototype Angular application running to display the buses at specific bus stops.

Nothing fancy here as I have not gotten the final design nailed down. Behind the scene, I was using purely bootstrap with Angular 11 to build this app.

While building the app, I came across a situation where the Angular Http Client is unable to connect properly to the LTA API.

It took me an hour of troubleshooting before I realised it was due to CORS caused by the browser. The API the app was calling is not configured to accept the OPTIONS request and returned a 401 error.

Recommendations by other smarter developers indicated I should use a proxy server or separate backend to make the call to such an API.

This is when I decided I will build the backend using Spring Boot…

Here comes Micronaut!

When my colleagues and I were heading out for lunch, one of them mentioned something about Micronaut.

A quick google search revealed that it is the alternative to Spring Boot. It is lightweight and starts up much faster.

It sounded good to me as I know how much time a Spring Boot application takes to start when there are a lot of dependencies. And considering that I am running the application a Raspberry PI, having something lightweight would be good for performance and power consumption.

But I can’t just take the word of some article. I had to see it for myself. And I also wanted to learn something new in the process.

Using Micronaut

Setting it up to use in a project was a relatively painless process.

I installed SDKMAN! on my development machine as it was recommended on the download page of micronaut.io. I followed the SDKMAN! setup process mentioned here. After that, I installed micronaut 2.3.0.

Creating a Micronaut app was as easy as ABC. Following through this article and you will have a project environment running.

Once the IntelliJ project is ready, I got down to developing the backend by following TDD. Here are some codes from the test class for the API controller.

@Test
    void testBusStopResourceShouldReturn200() {
        HttpResponse response = client.toBlocking().exchange(GET("/api"));
        assertThat(response.code()).isEqualTo(200);
    }

    @Test
    void testApiShouldReturnValidResponseWhenGivenValidQueryString() {
        HttpResponse<BusStopDTO> response = client.toBlocking().exchange(GET("/api/busstops?busStopCode=12345"), BusStopDTO.class);
        assertThat(response.code()).isEqualTo(200);
        assertThat(response.body()).isNotNull();
    }

    @Test
    void testApiShouldReturnErrorResponseWhenNotGivenValidQueryString() {

        assertThatThrownBy(() -> {
            HttpResponse<BusStopDTO> response = client.toBlocking().exchange(GET("/api/busstops"), BusStopDTO.class);
        }).isInstanceOf(HttpClientResponseException.class);

    }

Comparing this with JUnit test, there’s nothing really fancy or interesting.

On the other hand, I discovered something interesting with how Micronaut supports URL templates. Below is a snippet of the controller class that will serve the bus stop information.

@Controller("/api")
public class BusStopResource {

    @Get
    @Produces(MediaType.TEXT_PLAIN)
    public String index(){
        return "";
    }


    @Get("/busstops{?busStopCode}")
    @Produces(MediaType.APPLICATION_JSON)
    public HttpResponse<BusStopDTO> getBusStop(@Nullable String busStopCode){
        if (StringUtils.isEmpty(busStopCode)){
            return HttpResponse.badRequest();
        }

        return HttpResponse.ok(new BusStopDTO("12345", "TestName"));
    }

}

The difference here is query string parameters are all optional in Micronaut by default. @Nullable for each query parameter is necessary as the app will not compile if it is not done. If a particular parameter is required, validation of that parameter has to be handled in the code. Spring MVC on the other hand allow you to define an optional parameter with the use of Java 8 Optional.

Micronaut comes with support for mocking out of the box.

As far as I know, Spring Framework does not come with mocking support out of the box. Mockito seems to be the way to go but I could be wrong. Do let me know if that’s the case.

If you want to mock a service class that is used for connecting to external API, you can do so with @MockBean. To test if the mock is called, I use Mockito’s when and thenReturn methods.


@MicronautTest
public class PublicTransportServiceTest {

    @Inject
    LtaServiceAdapter ltaServiceAdapter;

    @Test
    void testShouldReturnBusStopDetailsWhenGivenValidBusStopCode() {
        when(ltaServiceAdapter.getBusArrival("12345")).thenReturn(new BusStop("12345", "TestBusStop"));
        PublicTransportService publicTransportService = new PublicTransportService(ltaServiceAdapter);
        BusStop busStop =publicTransportService.getBusServiceForBusStop("12345");
        assertThat(busStop).isNotNull();
        assertThat(busStop.getBusStopCode()).isEqualTo("12345");

    }

    @Primary
    @MockBean(MockLtaServiceAdapter.class)
    LtaServiceAdapter ltaServiceAdapter(){
        return mock(LtaServiceAdapter.class);
    }

}

As seen above, @Primary is a micronaut annotation that indicate a injectable service/class is the main one to use. In the app’s case, it was necessary as there was another class that implements the same interface and Micronaut wasn’t able to differentiate. There’s nothing new about this as the same annotation can also be found in Spring Framework.

The other difference between Micronaut and Spring is the use of @Inject to perform dependency injection for Micronaut, whereas for Spring Framework the default annotation for dependency injection is @Autowired.

@Inject is more portable since it is part of the JavaEE specification, specifically the JSR-330. Various other dependency injection framework such as Google Guice also uses this. In turn, this allows developers to change their dependency injection framework much more easily.

But, it is also important to note that you can configure your Spring-based projects to use @Inject.

Last but not least, Micronaut’s startup time is indeed faster. My unscientific/subjective judgement of the startup time put it at around 2 seconds. If my memory serves, Spring Boot takes about five to ten seconds on average to complete start up. It might take even longer if the application is huge and have lots of dependencies to manage.

Other than what I have mentioned, I’ll admit I hadn’t gone too far in to be able to tell whether Micronaut is superior to Spring Boot.

What’s next?

I will continue to build on my existing knowledge of Micronaut and Angular and finish the pet project. You can follow along what I’m doing at the following repositories:

  1. Angular Frontend
  2. Java/Micronaut Backend

Published by

Brandon Lim

I'm a software engineer and writing is my passion.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s