Back to Posts

Reactive Kotlin vs Java

Posted in Programming

For me the best way to learn something is by example, so instead to create HelloWords I’ve been translating my Java Reactive Spring 5 Webflux example into Kotlin, and now that is done is time to analyze the results.

I’m not going to talk about performance here, I’ve done JMeter load tests on both services and they virtual identical, response times are just decimals apart. However sometimes Kotlin seams to perform better, I’ll not get into conclusions until I research more.

First lest look at how many life of code we have create for each project:

Lines of Code Src Test
Java 1004 1172
Kotlin 721 1017


This is a expected result since Kotlin syntax will be always shorten and easer to understand.

Now when we look at the maxim complexity reported by https://codebeat.co

Complexity Max
Java 45
Kotlin 8


I think we need to do a deep down on this.

I’ve need to modify some line breaks in order to fit the web, please check the repos

Let’s look at one of the methods in the more complex class in Java:

  Mono<SunriseSunset> createResult(final Mono<GeoTimesResponse> geoTimesResponseMono) {
      return geoTimesResponseMono.flatMap(geoTimesResponse -> {
          if ((geoTimesResponse.getStatus() != null) && (geoTimesResponse.getStatus()
              .equals(STATUS_OK))) {
              return Mono.just(new SunriseSunset(geoTimesResponse.getResults().getSunrise(),
                      geoTimesResponse.getResults().getSunset()));
          } else {
              return Mono.error(new GetSunriseSunsetException(SUNRISE_RESULT_NOT_OK));
          }
      });
  }

And the equivalent method for the same class in Kotlin:

  open internal fun createResult(geoTimesResponseMono: Mono<GeoTimesResponse>) =
    geoTimesResponseMono.flatMap {
        with(it){
            if (status == STATUS_OK) with(results) { SunriseSunset(sunrise, sunset).toMono() }
            else GetSunriseSunsetException(SUNRISE_RESULT_NOT_OK).toMono()
        }
    }

Many times this is because of the extensions system that allow to write really tide code.

Let’s look at one of the methods in one of the handler class:

  Mono<ServerResponse> serverResponse(Mono<LocationResponse> locationResponseMono) {
      return locationResponseMono.flatMap(locationResponse ->
              ServerResponse.ok().body(Mono.just(locationResponse), LocationResponse.class));
  }

And the equivalent method for the same class in Kotlin:

  fun serverResponse(locationResponseMono: Mono<LocationResponse>): Mono<ServerResponse> =
    locationResponseMono.flatMap { ok() withBody it }

In fact spring framework has create custom extensions for Kotlin.

Let’s look at our api router function class:

  static RouterFunction<?> doRoute(final ApiHandler apiHandler, final ErrorHandler errorHandler) {
      return
              nest(path(API_PATH),
                  nest(accept(APPLICATION_JSON_UTF8),
                      route(GET(LOCATION_WITH_ADDRESS_PATH), apiHandler::getLocation)
                      .andRoute(POST(LOCATION_PATH), apiHandler::postLocation)
                  ).andOther(route(RequestPredicates.all(), errorHandler::notFound))
              );
  }

And the equivalent class in Kotlin:

  fun doRoute() = router {
      (accept(APPLICATION_JSON_UTF8) and API_PATH).nest {
          GET(LOCATION_WITH_ADDRESS_PATH)(handler::getLocation)
          POST(LOCATION_PATH)(handler::postLocation)
          path(ANY_PATH)(errorHandler::notFound)
      }
  }

Definitely Kotlin is more simpler and readable, but this is not only the main code lest check the test for our tests.

Testing our ThrowableTranslator in Java

  @Test
  void translatePathNotFoundExceptionTest() throws Exception {
    assertThat(PathNotFoundException.class, translateTo(HttpStatus.NOT_FOUND));
  }

And the same test in Kotlin

  @Test
  fun translatePathNotFoundExceptionTest() {
      PathNotFoundException::class `translates to` HttpStatus.NOT_FOUND
  }

But lets use a more complex test that includes mocking.

Testing one of the services error in Java

  @Test
  void getLocationNotFoundTest() {
      ServerRequest serverRequest = mock(ServerRequest.class);
      when(serverRequest.pathVariable(ADDRESS_VARIABLE)).thenReturn(GOOGLE_ADDRESS);
      doReturn(LOCATION_NOT_FOUND).when(geoLocationService).fromAddress(any());
      doReturn(SUNRISE_SUNSET).when(sunriseSunsetService).fromGeographicCoordinates(any());

      ServerResponse serverResponse = apiHandler.getLocation(serverRequest).block();
      assertThat(serverResponse.statusCode(), is(HttpStatus.NOT_FOUND));
      ErrorResponse error = HandlersHelper.extractEntity(serverResponse, ErrorResponse.class);
      assertThat(error.getError(), is(NOT_FOUND));

      reset(geoLocationService);
      reset(sunriseSunsetService);
  }

And the same test in Kotlin

  @Test
  fun getLocationNotFoundTest(){
      (geoLocationService `will return` LOCATION_NOT_FOUND).fromAddress(any())
      (sunriseSunsetService `will return` SUNRISE_SUNSET).fromGeographicCoordinates(any())
      val serverRequest = mock<ServerRequest>()
      (serverRequest `will return` GOOGLE_ADDRESS).pathVariable(ADDRESS_VARIABLE)

      val serverResponse = apiHandler.getLocation(serverRequest).block()
      serverResponse.statusCode() `should be` HttpStatus.NOT_FOUND
      val errorResponse : ErrorResponse = serverResponse.extractEntity()
      errorResponse.message `should equal to` NOT_FOUND

      geoLocationService reset `mock responses`
      sunriseSunsetService reset `mock responses`
  }

In these cases the number of lines is not the key factor but the readability of the Kotlin test is great.

Conclusions

With a syntax that make things simpler and more readable I’ll stick with Kotlin for my personal projects for a while meanwhile I still learning Reactive Programming.

About Juan Medina
I'm just a normal geek that code all kind of stuff, from complex corporate applications to games.

Games, music, movies and traveling are my escape pods.

Read Next

Why we should use functional programming with Kotlin?