micronaut-core icon indicating copy to clipboard operation
micronaut-core copied to clipboard

@JsonFormat (jackson) not working when no explicity @Body speficied

Open volnei opened this issue 2 years ago • 6 comments

Expected Behavior

Body need to be parsed using Jackson annotations even when not explicity annotated with @Body. When trying to use @Body annotation we can't use @RequestBean due to the bean is replaced with a new instance to fill body params.

Actual Behaviour

Body was parsed but not respecting Jackson Annotations like @JsonFormat(...)

Steps To Reproduce

Just run the follow test in any Micronaut Application

import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.time.LocalDate;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonFormat;

import org.junit.jupiter.api.Test;

import io.micronaut.core.annotation.Introspected;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.annotation.RequestBean;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.runtime.server.EmbeddedServer;
import io.micronaut.security.annotation.Secured;
import io.micronaut.security.rules.SecurityRule;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;

@MicronautTest
public class TestDate {

    @Inject
    EmbeddedServer embeddedServer;

    @Test
    void testBindDate() {
        String inputId = "abc";
        String inputDate = "2022-01-23 00";

        TestClient testClient = embeddedServer.getApplicationContext().getBean(TestClient.class);
        assertNotNull(testClient.test(inputId, Map.of("date", inputDate)));
    }

    @Client("/api/test")
    static interface TestClient {

        @Post("/{id}")
        public String test(@PathVariable("id") String id, @Body Map<String, Object> body);
    }

    @Secured(SecurityRule.IS_ANONYMOUS)
    @Controller("/test")
    static class TestController {

        @Post("/{id}")
        public String test(@RequestBean TestPojo testPojo) {
            return testPojo.getDate().toString() + testPojo.getId();
        }
    }

    @Introspected
    static class TestPojo {

        @PathVariable("id")
        private String id;

        @JsonFormat(pattern = "yyyy-MM-dd HH")
        private LocalDate date;

        public void setDate(LocalDate date) {
            this.date = date;
        }

        public LocalDate getDate() {
            return date;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
    }
}

Environment Information

Any

Example Application

No response

Version

3.5.0

volnei avatar May 26 '22 04:05 volnei

i dont think jackson is used to populate TestPojo, so not sure why this should work. it's a separate mechanism

yawkat avatar May 27 '22 10:05 yawkat

Hi Jonas, so what is the correct way to set the LocalDateTime/LocalDate format? Thanks

marciomunhoz avatar May 27 '22 14:05 marciomunhoz

please try io.micronaut.core.convert.format.Format

yawkat avatar May 27 '22 14:05 yawkat

I tried with @Format annotation but it didn't work either

marciomunhoz avatar May 27 '22 14:05 marciomunhoz

@yawkat Did you run the test I posted? Did you make it work? If yes, please post the answer. If not, let's wait for someone who knows.

https://github.com/micronaut-projects/micronaut-core/issues/2156

volnei avatar May 27 '22 14:05 volnei

#2156 does not apply here, TestPojo contains a PathVariable so it can't be parsed from json (i.e. through jackson)

The test case is a bit problematic in this regard, it has mismatched path, sends a json body but expects query params on the controller side, and it uses LocalDate with a format that has a time component. it cannot work in its current state

yawkat avatar May 27 '22 14:05 yawkat