Last active
December 3, 2019 10:43
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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