2

My DELETE request accepts a list of Items that should be deleted.

I want to validate that the request body is a valid list of Item objects.

The example given in the Javalin docs doesn't mention lists.

In order to get the code to compile, I had to do this:

    TypedValidator<List> requestValidator = ctx.validatedBodyAsClass(List.class);
    List<Item> items = requestValidator.getOrThrow();
    logger.info("Received delete request for {}", Arrays.toString(items.toArray()));
    logger.info("items is type {}", items.getClass());
    for (Item item : items) {
        logger.info("Deleting {}", item.name);
    }

The validation passes and the ctx body is printed correctly in the following line. The problem is, there is an unchecked assignment at getOrThrow() and indeed the loop doesn't work:

[qtp1679441380-34] INFO com.myorg.MyClass - Received delete request for [{name=FooName, type=BarType}]
[qtp1679441380-34] INFO com.ericsson.cdzm.ws.controllers.ScheduleController - items is type class java.util.ArrayList
[qtp1679441380-34] WARN io.javalin.core.ExceptionMapper - Uncaught exception
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.myorg.Item
    at  com.myorg.MyClass.deleteItems(MyClass.java:51)

Edit: The java.util.LinkedHashMap seems to be because actually, items is of type ArrayList<LinkedHashMap<String,String>>. In other words, Javalin didn't parse or validate the body contents at all! It only converted the Json name=value mappings into a Java Map.

What would be a better way to validate the incoming Json and parse it to a list of Items?

I've tested on Javalin 2.6.0 and 2.8.0.

Jolta
  • 2,620
  • 1
  • 29
  • 42

1 Answers1

2

What I had missed, and can't find in the Javalin docs, was that I have to use array types rather than parameterized Collection types. This works:

    TypedValidator<Item[]> requestValidator = ctx.bodyValidator(Item[].class);
    List<Item> items = Arrays.asList(requestValidator.get());

Still, would love to know why this is - I suspect it is related to Java's type system somehow?

I could also directly access the Jackson ObjectMapper object and use it like you would use Jackson. The drawback is that I don't benefit from Javalin's automatic throwing of BadRequestResponse etc. I think using array types is a small price to pay for this.

    try {
        List<ScheduleRequest> items =  JavalinJackson.getObjectMapper().readValue(ctx.body(), new TypeReference<List<ScheduleRequest>>(){});
    } catch (IOException e) {
       throw new BadRequestResponse(e.getMessage());
    }
Jolta
  • 2,620
  • 1
  • 29
  • 42