0

The idea is to avoid the introduction of DTO. A user submits post request that shouldn't have calculationSeed. This field must be set by service and included into a response. MapperFeature.USE_GETTERS_AS_SETTERS not working. I am trying to avoid messy programmatic configuration using filters. The problem is that ow.writeValueAsString(john) includes the field in request in JUnit test.

Person

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonPropertyOrder({"firstName", "lastName", "age", "calculationSeed"})
public class Person {
    @NotNull
    @JsonProperty("first_name")
    private String firstName;

    @NotNull
    @JsonProperty("last_name")
    private String lastName;

    private int age;

    @JsonIgnore
    private double calculationSeed;

    @JsonProperty
    public double getCalculationSeed() {
        return calculationSeed;
    }

    @JsonIgnore
    public void setCalculationSeed(double calculationSeed) {
        this.calculationSeed = calculationSeed;
    }
}

Test

@SpringJUnitConfig(DataCollectorE2EIT.Config.class)
public class e2EIT {

    @Configuration
    static class Config {}

    WebTestClient client;

    @BeforeEach
    void setUp(ApplicationContext context) {
        client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build();
    }

    static ObjectMapper mapper;
    static ObjectWriter ow;

    @BeforeAll
    public static void setUp() {
        mapper = new ObjectMapper().disable(MapperFeature.USE_GETTERS_AS_SETTERS);
        ow = mapper.writer().withDefaultPrettyPrinter();
    }

    @Test
    public void givenPersonData_whenPostRequest_then() throws Exception {
        Person john = Person.builder().firstName("John").lastName("Smith").age(25).build();

        client.post()
                .uri("/api/persons")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(ow.writeValueAsString(john))
                .exchange()
                .expectStatus().isCreated()
                .expectBody(Person.class)
                .consumeWith(result -> {
                    assertThat(result.getResponseBody()).isNotNull();
                    assertEquals(0.09482345680132348, result.getResponseBody().getCalculationSeed());
                })
                .returnResult();
    }
}

logs

> POST http://localhost:8080/api/persons
> WebTestClient-Request-Id: [1]
> Content-Type: [application/json]
> Content-Length: [98]

{
  "first_name" : "John",
  "last_name" : "Smith",
  "age" : 25,
  "calculationSeed" : 0.0
}

< 201 CREATED Created
< Content-Type: [application/json]
< Transfer-Encoding: [chunked]
< Date: [Mon, 19 Oct 2020 15:26:01 GMT]

{"first_name":"John","last_name":"Smith","age":25,"calculation_seed":0.09482345680132348}
J.Olufsen
  • 13,415
  • 44
  • 120
  • 185

1 Answers1

0

One of the easiest solution would be that you change calculationSeed to of boxed type Double. Primitive double can not be defaulted to null that would be ignored so it will be 0.0.

But more generally the issue that I have faced is that people tend to use the same DTO both for input & for output even if they are not the same as it seems to be in your case.

In your case it would be also easy to make two DTOs like:

// annotations...
public class PersonDTO {
    // all but calculationSeed
}

and

// annotations...
public class PersonDTOOut extends Person {
    private double calculationSeed;        
}

and then use these accordingly.

pirho
  • 11,565
  • 12
  • 43
  • 70