Skip to content

Instantly share code, notes, and snippets.

@reyabreu
Last active December 3, 2019 10:43
Show Gist options
  • Save reyabreu/a7e23ad511c73d13c441c7313e48b36d to your computer and use it in GitHub Desktop.
Save reyabreu/a7e23ad511c73d13c441c7313e48b36d to your computer and use it in GitHub Desktop.
Ensure properly created ObjectMapper is used in Retrofit's JacksonConverterFactory to serialise embedded Java Optionals in request body
@RunWith(SpringRunner.class)
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class })
@SpringBootTest(
classes = { TestFooRequest.FooController.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@AutoConfigureMockMvc(secure = false)
public class TestFooRequest {
private static final Logger logger = LoggerFactory.getLogger(TestFooRequest.class);
@Autowired
private ObjectMapper _objectMapper;
@LocalServerPort
private int _randomServerPort;
private FooClient _fooClient;
@Before
public void setUp() throws MalformedURLException {
_fooClient = new Retrofit.Builder()
.baseUrl(new URL("http://localhost:" + _randomServerPort).toExternalForm())
.client(new OkHttpClient())
.addCallAdapterFactory(Java8CallAdapterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GuavaConverterFactory.create())
.addConverterFactory(JacksonConverterFactory.create(_objectMapper))
.build()
.create(FooClient.class);
}
@Test
public void test_toJson_validAmount() throws Exception {
String jsonString = _objectMapper.writeValueAsString(new FooResponse(100, "FooValue", 1234.25));
logger.info("{}", jsonString);
assertThat(jsonString).isEqualTo("{\"id\":100,\"value\":\"FooValue\",\"amount\":1234.25}");
}
@Test
public void test_fromJson_validAmount() throws Exception {
String jsonString = "{\"id\":200,\"value\":\"FromString\",\"amount\":1234.25}";
logger.info("{}", jsonString);
final FooResponse fooResponse = _objectMapper.readValue(jsonString, FooResponse.class);
assertThat(fooResponse).isNotNull();
assertThat(fooResponse.id).isEqualTo(200);
assertThat(fooResponse.value).isPresent().contains("FromString");
assertThat(fooResponse.amount).isPresent().contains(1234.25);
}
@Test
public void test_toJson_nullAmount() throws Exception {
String jsonString = _objectMapper.writeValueAsString(new FooResponse(100, "FooValue", null));
logger.info("{}", jsonString);
assertThat(jsonString).isNotEmpty();
}
@Test
public void test_fromJson_nullAmount() throws Exception {
String jsonString = "{\"id\":200,\"value\":\"FromString\"}";
logger.info("{}", jsonString);
final FooResponse fooResponse = _objectMapper.readValue(jsonString, FooResponse.class);
assertThat(fooResponse).isNotNull();
assertThat(fooResponse.id).isEqualTo(200);
assertThat(fooResponse.value).isPresent().contains("FromString");
assertThat(fooResponse.amount).isNotPresent();
}
@Test
public void createFoo_BodyWithOptionals_shouldNotFail() throws ExecutionException, InterruptedException {
FooResponse fooResponse = _fooClient.createFoo(new FooRequest("FooValue", 4488.88)).get();
assertThat(fooResponse).isNotNull();
assertThat(fooResponse.id).isEqualTo(7827);
assertThat(fooResponse.value).isPresent().contains("FooValue");
assertThat(fooResponse.amount).isPresent().contains(4488.88);
}
interface FooClient {
@POST("api/foo")
CompletableFuture<FooResponse> createFoo(@Body FooRequest fooRequest);
}
static class FooRequest {
public final String value;
public final Optional<Double> amount;
@JsonCreator
public FooRequest(@JsonProperty("value") String value,
@JsonProperty("amount") Double amount) {
this.value = value;
this.amount = Optional.ofNullable(amount);
}
}
static class FooResponse {
public final Integer id;
public final Optional<String> value;
public final Optional<Double> amount;
@JsonCreator
public FooResponse(@JsonProperty("id") Integer id,
@JsonProperty("value") String value,
@JsonProperty("amount") Double amount) {
this.id = id;
this.value = Optional.ofNullable(value);
this.amount = Optional.ofNullable(amount);
}
}
@RestController
@RequestMapping("/api/foo")
static class FooController {
@PostMapping
public FooResponse createFoo(@RequestBody FooRequest fooRequest) {
return new FooResponse(7827,
fooRequest.value,
fooRequest.amount.orElse(0.0));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment