retrofit
retrofit copied to clipboard
[Bug?] Retrofit Jackson Converter doesn't work with Polymorphism
I'm trying to get Retrofit to work with polymorphic types, something like this:
public static interface Vehicle {
}
public static class Car implements Vehicle {
@JsonProperty("type")
public String type() { return "car"; }
}
public static class Lorry implements Vehicle {
@JsonProperty("type")
public String type() { return "lorry"; }
@JsonProperty("cargo")
private String cargo() { return "toys"; }
}
Here's my service:
public interface Service {
@POST("/api/")
public Call<String> upload(@Body Vehicle vehicle);
}
And here's my test:
@Test
public void test() throws IOException {
final OkHttpClient client = new OkHttpClient();
var retrofit = new Retrofit.Builder()
.addConverterFactory(JacksonConverterFactory.create())
.baseUrl("http://whatever/") //We fail before we hit this!
.client(client)
.build();
Service service = retrofit.create(Service.class);
var call = service.upload(new Car());
call.execute();
}
This gives the following error:
java.lang.IllegalArgumentException: Unable to convert SimpleRetrofitTest$Car@14bdbc74 to RequestBody (parameter #1)
for method Service.upload
at retrofit2.Utils.methodError(Utils.java:53)
...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class SimpleRetrofitTest$Car and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
...
at retrofit2.converter.jackson.JacksonRequestBodyConverter.convert(JacksonRequestBodyConverter.java:34)
at retrofit2.converter.jackson.JacksonRequestBodyConverter.convert(JacksonRequestBodyConverter.java:24)
at retrofit2.ParameterHandler$Body.apply(ParameterHandler.java:411)
... 70 more
It's struggling to serialize from the interface to the class. The code works fine if I change the API to: public Call<String> upload(@Body Car vehicle);
, so a Car
can definitely be serialised. But the JacksonConverter seems to struggle with the polymorphism in this instance.
I've got a complete Gist for this test here: https://gist.github.com/msmerc/4a53b51200bd1e80ce1e9f7ffe3efb16
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = Car.class, name = "car"), @JsonSubTypes.Type(value = Lorry.class, name = "lorry") }) public static interface Vehicle { }