'Body of ResponseEntity is null even though the object given in its constructor is not null

Alright, so I got two APIs. One is doing persistance only (let's call it 'A') and the other one is some kind of calculator ('B').
What I am trying to do is, that if you call a @GetMapping-method in B, that B will get the data with the given ID from A, maps the JSON into a Java object, does all the calculation and when the calculation is done, post the result to A.
All that with one Request.
Everything works fine until I want to post the result to A. In this case, I have an object of my class "TcoResult" as a parameter for the "post-method". When I call the to-String on that object in this very method, I get all the values it has and everything is fine, but if I return it as body of a ResponseEntity, that ResponseEntity returns an empty JSON (I guess?) and the logger tells me
RequestResponseBodyMethodProcessor : Nothing to write: null body.
Let's kick off with a snippet of my model. All 42 values are annotated with @JsonProperty, it contains an empty and full constructor, getters and setters and a to-String method.

public class TcoResult {

    @JsonProperty("id")
    private float id;
    @JsonProperty("emissionCostsCO2Share")
    private float emissionCostsCO2Share;
    @JsonProperty("emissionCostsFineDustShare")
    private float emissionCostsFineDustShare;
    @JsonProperty("emissionCostsNoxShare")
    private float emissionCostsNoxShare;
    @JsonProperty("emissionCostsTotal")
    private float emissionCostsTotal;

    ...

My Controller class in B:

@RestController
public class DataApiController implements ResultEventListener {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    DataApiService dataApiService;


    @GetMapping(
            value = "calculate/{id}",
            produces = "application/json;charset=UTF-8"
    )
    public void getTcoInputFromDataApi(@PathVariable int id) {
        dataApiService.setResultEventListenerController(this);
        dataApiService.getTcoInputFromDataApi(id);
    }

    @PostMapping(
            produces = "application/json;charset=UTF-8",
            consumes = "application/json;charset=UTF-8"
    )
    public ResponseEntity<Object> postTcoResultToDataApi(@RequestBody TcoResult tcoResult) {
        return dataApiService.postTcoResultToDataApi(tcoResult);
    }

    @Override
    public void onEvent() {
        this.postTcoResultToDataApi(dataApiService.getTcoResult());
    }


}

Via Postman, I call the getTcoInputFromDataApi-method with a GET-Request. This returns the object with the given ID from my DataApi.
Let's getto the Service class in B:

@Service
public class DataApiService implements ResultEventListener{

    @Autowired
    RestTemplate restTemplate;

    private Logger logger = LoggerFactory.getLogger(DataApiService.class);
    private ResultEventListener resultEventListenerController;

    private final String URI_TCORESULT = "resultTco";
    private final String URI_TCOINPUT_ID = "inputTco/{id}";

    private CalculationFactory calculationFactory;
    private TcoInput tcoInput;
    private TcoResult tcoResult;


    // GET input for the tco from the DataApi by id
    public void getTcoInputFromDataApi(int id) {
        Map<String, String> params = new HashMap<>();
        params.put("id", Integer.toString(id));

        tcoInput = restTemplate.getForObject(URI_TCOINPUT_ID, TcoInput.class, params);
        logger.info("Successfully read the tco input object from the DataApi");
        this.onEvent();
    }

    // POST the results to the DataApi
    public ResponseEntity<Object> postTcoResultToDataApi (TcoResult tcoResult123) {
        logger.info(tcoResult123.toString());
        // TcoResult toReturn = restTemplate.postForObject(URI_TCORESULT, tcoResult123, TcoResult.class);
        //return new ResponseEntity<>(toReturn, HttpStatus.CREATED);
        return new ResponseEntity<>(tcoResult123, HttpStatus.CREATED);
    }


    private void calculateResults(TcoInput tcoInput) {
        calculationFactory = new CalculationFactory(tcoInput);
        JSONDataOutput jsonDataOutput = calculationFactory.calculateAllCosts();
        tcoResult = calculationFactory.getResultTco();
    }

    public void setResultEventListenerController(ResultEventListener resultEventListenerController) {
        this.resultEventListenerController = resultEventListenerController;
    }

    public TcoResult getTcoResult() {
        return tcoResult;
    }

    @Override
    public void onEvent() {
        logger.info("Calculating results...");
        calculateResults(this.tcoInput);
        logger.info("Calculations are done!");
        if (tcoResult != null) {
            logger.info("Calling listener of controller");
            resultEventListenerController.onEvent();
        }
    }


}

As you can see, I work with custom listeners, so that logic gets triggered as soon as the calculation is done. All that works as intended.
The problem arises, when the logic reraches the postTcoResultToDataApi-method. For presentation's sake I just returned a new ResponseEntity with the TcoResult as paramter.
The commented code is the one I want to execute, but if I do so, my DataApi responds with a 422 code, which I implemented in my validation logic (because the given object somehow is null).
The controller of the DataApi are pretty basic and just save an object (when POST) or return a ResponseEntity with an object (when GET).
Here you can see the code of B exemplarily (as I said, nothing special).

@RestController
public class ResultTcoSimulationController {

    private ResultTcoSimulationService resultTcoSimulationService;

    @Autowired
    public ResultTcoSimulationController(ResultTcoSimulationService resultTcoSimulationService) {
        this.resultTcoSimulationService = resultTcoSimulationService;
    }

    @PostMapping(
            value = "/resultTco",
            consumes = "application/json;charset=UTF-8",
            produces = "application/json;charset=UTF-8"
    )
    public ResponseEntity<Object> addResultForTcoSimulation(@RequestBody ResultTco resultTco) {
        return resultTcoSimulationService.addResultForTcoSimulation(resultTco);
    }

    @GetMapping(
            value = "/resultTco/{id}",
            produces = "application/json;charset=UTF-8"
    )
    public ResponseEntity<Object> readResultForTcoSimulation(@PathVariable int id) {
        return resultTcoSimulationService.readResultForTcoSimulation(id);
    }

    ...

and the service class:

@Component
public class ResultTcoSimulationService {

    @Autowired
    @Lazy
    private ResultTcoSimulationRepository resultTcoSimulationRepository;

    Logger logger = LoggerFactory.getLogger(ResultTcoSimulationService.class);

    // CREATE result for the TCO simulation
    public ResponseEntity<Object> addResultForTcoSimulation(ResultTco resultTco) {
        String exceptionMessage;
        try {
            validateObjectForPost(resultTco);
            resultTcoSimulationRepository.save(resultTco);
            logger.info("Successfully created the result for the TCO simulation with the id = " + resultTco.getId());
            return new ResponseEntity<>(resultTco, HttpStatus.CREATED);
        } catch(IllegalIdException e) {
            exceptionMessage = e.getMessage();
            return new ResponseEntity<>(exceptionMessage, HttpStatus.CONFLICT);
        } catch(IllegalPassingParameterException e) {
            exceptionMessage = e.getMessage();
            return new ResponseEntity<>(exceptionMessage, HttpStatus.UNPROCESSABLE_ENTITY);
        }
    }

    ...

In the end, I just don't get why - in B - when wanting to post the object to A, the very instanciated object is null, when given as a parameter of the ResponseEntity, but has perfectly fine values, when printed in the logger.

I don't know if this is of any interest, but if I print that object in the logger with logger.info(tcoResult123.toString()); it calls the to-String method, if the line
TcoResult toReturn = restTemplate.postForObject(URI_TCORESULT, tcoResult123, TcoResult.class); is executed, the terminal says
Writing *basically the toString of the object* with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source