1

Versions:

lombok: 1.18.20 spring-boot: 2.5.4

lombok.config (using default generated by IntelliJ)

# add @lombok.Generated annotation to all Lombok generated methods
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true

POJOs

Payload.java

@Jacksonized @Builder @Value
public class Payload<T> {
    @Getter(AccessLevel.NONE)
    private T content;

    /**
     * @return payload content
     */
    public T get() {
        return content;
    }
}

ApiRequest.java

@Jacksonized @Builder @Value
public class ApiRequest<T> {
    private Date timestamp;
    private Payload<T> payload;
}

Metadata.java

@Jacksonized @Builder(toBuilder = true) @Value
public class Metadata {
    private String element;
    private String threshold;
    private String groupType;
    private String groupId;
    private String groupName;
    private String groupPath;
    private Instant from;
    private Instant to;

}

MyRestController.java

@Slf4j
@Validated
@RestController
@RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
@RequestScope
public class MyRestController {
    @RequestMapping(
            path = "/process",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ApiResponse process(@RequestBody ApiRequest<List<Metadata>> apiRequest) {
        log.info("Received request: " + apiRequest);
        return null; // Ignore for now
    }

    /*public ApiResponse process(@RequestBody String json) {
        log.info("Received request: " + json);
        return null; // Ignore for now
    }*/
}

TestClass.class

public class TestClass {

    public static void main(String[] args) throws Exception {
        String fromStr = "2021-09-05T00:00:00Z";
        String toStr = "2021-09-11T23:59:59Z";
        Instant from = Instant.parse(fromStr);
        Instant to = Instant.parse(toStr);
        String groupName = "SomeGroupName";
        String groupPath = "SomeGroupPath";

        List<Metadata> metadataList = new ArrayList<>();
        metadataList.add(Metadata.builder().element("e1").threshold("48").groupName(groupName).groupPath(groupPath).from(from).to(to).build());
        metadataList.add(Metadata.builder().element("e2").threshold("35").groupName(groupName).groupPath(groupPath).from(from).to(to).build());
        metadataList.add(Metadata.builder().element("e3").threshold("90").groupName(groupName).groupPath(groupPath).from(from).to(to).build());

        Payload<List<Metadata>> payload = Payload.<List<Metadata>>builder().content(metadataList).build();
        ApiRequest<List<Metadata>> apiRequest = ApiRequest.<List<Metadata>>builder().payload(payload).build();

        RestTemplate rt = new RestTemplate();
        final String baseUrl = "http://localhost:8080/test/process";
        URI uri = new URI(baseUrl);
        ResponseEntity<ApiResponse> response = rt.postForEntity(uri, apiRequest, ApiResponse.class);
        ApiResponse r = response.getBody();
    }
}

When I run this setup, the MyRestController receives a null apiRequest. If I uncomment the commented out method in the controller, the stringified json is also null. I saw examples on Internet where people claim that they have been able to use @Jacksonized to serialize and deserialize immutable POJOs.

  1. Is there something wrong I am doing that is failing the serialization?
  2. Let's say the serialization works, then do I need some special handling for ApiResponse to get deserialized?

Current outcome when running the program:

Received request: {"timestamp":null,"payload":{}}

Note:

I already looked at this discussion here. But I am more inclined toward making @Jacksonized work.

UPDATE - SOLVED

The problem was with the Payload.java POJO. Modifying the POJO as below solved the problem:

@Jacksonized @Builder @Value
public class Payload<T> {
    @Getter(AccessLevel.NONE)
    private T content;

    /**
     * @return payload content
     */
    @JsonProperty("content") // ADDED THIS TO TELL JACKSON TO USE THIS GETTER FOR content
    public T get() {
        return content;
    }
}
curious_brain
  • 391
  • 2
  • 17
  • Please add your solution as an answer instead of editing your question. (You can accept your own answer after a 2 days.) – Jan Rieke Dec 01 '21 at 06:58

1 Answers1

1

As @Jan Rike suggested, I am adding my solution as answer.

The problem was with the Payload.java POJO. Modifying the POJO as below solved the problem:

@Jacksonized @Builder @Value
public class Payload<T> {
    @Getter(AccessLevel.NONE)
    private T content;

    /**
     * @return payload content
     */
    @JsonProperty("content") // ADDED THIS TO TELL JACKSON TO USE THIS GETTER FOR content
    public T get() {
        return content;
    }
}

Without this, Jackson was looking for a getContent() method and failing because it didn't exist (due to @Getter(AccessLevel.NONE))

curious_brain
  • 391
  • 2
  • 17