0

I have a weird issue with a unit test and ResponseEntity. Here's the test:

@Test
@DirtiesContext
public void createEntityTest() {
    EntityRequestDTO requestDTO = new EntityRequestDTO();
    dto.setTitle("foo");
    dto.setDescription("bar");
    ResponseEntity<EntityResponseDTO> postResponse = 
        testRestTemplate.postForEntity("/api/test", dto, EntityResponseDTO.class);
    EntityResponseDTO responseDTO = postResponse.getBody();
    
    assertThat(responseDTO.getTitle()).isEqualTo("foo");
    assertThat(responseDTO.getDescription()).isEqualTo("bar");
    assertThat(responseDTO.getFullname()).isEqualTo("foobar");
}

The full name is set in the background by service. The issue is, this last assertion fails. getFullname() returns null. That may be because of several reasons, but, here's the controller endpoint:

@PostMapping("/api/test")
public ResponseEntity<EntityResponseDTO> create(@RequestBody EntityRequestDTO requestDTO) {
    Entity saved = entityService.add(requestDTO);
    EntityResponseDTO savedDto = new EntityResponseDTO(saved);
    URI location = ServletUriComponentsBuilder
                .fromCurrentRequest()
                .path("/{id}")
                .buildAndExpand(saved.getId())
                .toUri();
    ResponseEntity<EntityResponseDTO> resEntity = ResponseEntity.created(location).body(savedDto);
    System.out.println("Before: ResponseEntity in controller.");
    System.out.println(resEntity.getBody().getFullname());
}

However here, just before returning the ResponseEntity the System.out.println(resEntity.getBody().getFullname()) method prints foobar. I can't wrap my head around this. What is going on?

Note: I have @JsonIgnore on the fullname field because I want it to be present, but not shown in the response. When removing annotation, test passes.

IceMajor
  • 37
  • 5

1 Answers1

1

Using @JsonIgnore is the issue here. As the name suggests, @JsonIgnore annotation ignores the corresponding field in serialisation. That means it will not be included in your response. This does not affect what you are doing in your create method. Therefore it gets printed successfully.

Removing @JsonIgnore will resolve this. To read more on @JsonIgnore - https://www.tutorialspoint.com/jackson_annotations/jackson_annotations_jsonignore.htm

chameerar
  • 322
  • 1
  • 2
  • 8
  • Hi, thanks for answering. When receiving the `ResponseEntity` in the field, can I still receive JSON body without the field `fullname`, but still be able to read the value under it in tests (I've tried the `value` option of `@JsonIgnore`)? – IceMajor Jun 22 '23 at 15:39
  • And, if I understand correctly, the serialization happens when passing the object into `ResponseEntity`. How come, then, that the `ResponseEntity` in controller persists the `fullname` value? – IceMajor Jun 22 '23 at 15:48
  • 1
    Serialisation happens when you convert an object (`EntityResponseDTO` in this case) to a string (to a `JSON` in this case). What happens in your REST endpoint is that you serialise the `EntityResponseDTO` when sending it over as the response. That's why `fullname` is not available in the response. You can find it in the controller since you take it from the object in the controller side. – chameerar Jun 22 '23 at 16:20
  • More on serialisation - https://stackoverflow.com/questions/3316762/what-is-deserialize-and-serialize-in-json – chameerar Jun 22 '23 at 16:22
  • OK. I read it, but I still have no clue how to achieve what I want. I've stumbled upon `@JsonIgnore` on the getter, but `@JsonPropety` on the setter. I've stumbled upon `@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)`. I've stumbled upon class annotation. None of the solutions worked for me. I really am helpless. :/ – IceMajor Jun 22 '23 at 19:57
  • Could you explain more on what you are trying to achieve? If you don't want the `fullname` to be present in the response, then you can use `@JsonIgnore`. If you want to it to be present, then you should not use the `@JsonIgnore` annotation. – chameerar Jun 23 '23 at 03:41
  • I'd like the above test to pass. I'd like the fullname to not be present in the JSON response, but I'd still like to be able to get `fullname` by `getFullname()` method, which - currently - returns null. – IceMajor Jun 23 '23 at 08:57
  • Note: the fullname *is* present in controller. Not the test – IceMajor Jun 23 '23 at 09:00
  • If you don't want `fullname` to be present in the JSON response, then you have done correctly. That means on the receiving side there isn't a value received for `fullname`. Hence the `getFullname()` method gives a null. There isn't a way to get the value of fullname from the receiving end (Test method in your case) because the value never came with the response. Hope you understand this. – chameerar Jun 23 '23 at 14:14
  • Hm, okay. I was convinced there was a way to do so. Then, I have no clue what the `access` is for in `@JsonIgnore`. – IceMajor Jun 23 '23 at 16:22