Javalin: Context.json() does not throw checked exceptions that it actually throws

Created on 12 Mar 2019  路  5Comments  路  Source: tipsy/javalin

Actual behavior (the bug)
context.json() throws JsonParseException but I'm unable to catch it in a proper way.

Expected behavior
context.json() declares exceptions thrown by it.

To Reproduce
An example to generate a JsonParseException error:

import io.javalin.Javalin;

public final class Main {
  public static void main(String[] args) {
    Javalin app = Javalin.create().start(12345);
    app.post("/json", ctx -> ctx.result(ctx.bodyAsClass(TestClass2.class).getName()));
  }
}

final class TestClass2 {
  private String name;

  public String getName() {
    return name;
  }

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

Then a post of malformed JSON would trigger an exception, e.g. with "=" instead of ":":

wget --post-data='{"name"="name"}' localhost:12345/json -O /dev/null -q

You get:

[qtpxxxxxxxxxx-xx] WARN io.javalin.core.ExceptionMapper - Uncaught exception
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('=' (code 61)): was expecting a colon to separate field name and value
 at [Source: (String)"{"name"="name"}"; line: 1, column: 9]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804)
...

If I try to wrap it with try-catch:

try {
  ctx.result(ctx.bodyAsClass(TestClass2.class).getName());
} catch (JsonParseException e) {
  e.printStackTrace();
}

The compiler would complain:

Exception 'com.fasterxml.jackson.core.JsonParseException' is never thrown in the corresponding try block

This is an error that I can't ignore it like a warning.

Additional context
I'm doing something like this at the time being:

try {
  ctx.result(ctx.bodyAsClass(TestClass2.class).getName());
} catch (Exception e) {
  if (e instanceof JsonParseException) {
    e.printStackTrace();
  }
}

This at least allows me to compile, though there is an IDE warning highlighting:

Condition 'e instanceof JsonParseException' is always 'false' less
QUESTION

All 5 comments

Hi @azurvii. The context.json() function uses JavalinJson, which can be configured with any JSON library. For this reason, it can't throw JsonParseException, or any other specific exception.

Instead of wrapping things in a try-catch, consider using an exception mapper:

app.exception(JsonParseException.class, (e, ctx) -> {
    // handle exception here
});

@azurvii I'm going to close this now, please re-open if you need more help.

Thanks @tipsy. This is an interesting way of handling exceptions.

Hi @tipsy. It seems, that the solution provided here doesn't work anymore... There is no way neither to catch the json related exceptions (JsonParseException, JsonProcessingException etc.) nor to provide an alternative exception in e.g. JavalinJson.fromJsonMapper (which btw doesn't allow you to throw a checked one but that is another story).

The reason is that the default Context.bodyAsClass implementation simply discards the original exception and throws BadRequestResponse instead with a default message (and no cause populated).

Just wanted to double check with you :)

@avshenuk that's correct, you'll have to validate it manually if you want to catch your own exception.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

accron-1 picture accron-1  路  4Comments

maxemann96 picture maxemann96  路  5Comments

mkpaz picture mkpaz  路  4Comments

TobiasWalle picture TobiasWalle  路  3Comments

JosefEvAlloc picture JosefEvAlloc  路  5Comments