android - Retrofit2: serializer doesn't get called for @Field-annotated parameters -
i need send http put request custom json object in 1 of request's parameter. here problem: when use retrofit2, serializer doesn't called.
my object should looks this:
{ "ignore":["item1", "item2"] } when call directly works well:
final gson gson = new gsonbuilder() .registertypeadapter(mymodel.class, new mymodelserializer()) .create(); string s = gson.tojson(new mymodel(mymodel.actionname.accept, new arraylist<string>())); log.d("tag", s); i {"accept":[]}. when call retrofit see in logs this: d/okhttp: name=abc&items=ru.bartwell.myapp.mymodel%4010a3d8b
i make request code:
try { mymodel mymodel = new mymodel(mymodel.actionname.accept, new arraylist<string>()); response<resultmodel> response = getmyapi().getresult(1, "abc", mymodel).execute(); if (response.issuccessful()) { resultmodel resultmodel = response.body(); // handle resultmodel } } catch (exception e) { e.printstacktrace(); } myapi:
@formurlencoded @put("path/{id}") call<resultmodel> getresult(@path("id") long item, @field("name") @nonnull string name, @field("items") @nonnull mymodel mymodel); getmyapi() method:
public static myapi getmyapi() { final gson gson = new gsonbuilder() .registertypeadapter(mymodel.class, new mymodelserializer()) .create(); return new retrofit.builder() .baseurl(buildconfig.end_point_my_api) .client(myokhttpclient.create()) .addconverterfactory(gsonconverterfactory.create(gson)) .build() .create(myapi.class); } model:
public class mymodel { @nonnull private actionname mactionname; @nonnull private list<string> mitems = new arraylist<>(); public mymodel(@nonnull final actionname actionname, @nonnull final list<string> items) { mactionname = actionname; mitems = items; } @nonnull public actionname getactionname() { return mactionname; } @nonnull public list<string> getitems() { return mitems; } public enum actionname { accept("accept"), decline("decline"), ignore("ignore"); private string mname; actionname(@nonnull final string name) { mname = name; } public string getname() { return mname; } } } serializer:
public class mymodelserializer implements jsonserializer<mymodel> { @override public jsonelement serialize(@nonnull mymodel src, @nonnull type typeofsrc, @nonnull jsonserializationcontext context) { jsonobject obj = new jsonobject(); obj.add(src.getactionname().getname(), new gson().tojsontree(src.getitems())); return obj; } } how fix it?
this happens because @field-annotated parameters serialized stringconverter. override default behavior, need add converter.factory stringconverter method overridden:
.addconverterfactory(new converter.factory() { @override public converter<?, string> stringconverter(final type type, final annotation[] annotations, final retrofit retrofit) { // example check supported classes if ( type instanceof class ) { final class<?> clazz = (class<?>) type; if ( mymodel.class.isassignablefrom(clazz) ) { return (converter<object, string>) value -> gson.tojson(value, type); } } return super.stringconverter(type, annotations, retrofit); } }) then query parameter string this:
name=abc&items=%7b%22accept%22%3a%5b%5d%7d
(this %7b%22accept%22%3a%5b%5d%7d' uri-encoded {"accept":[]}).
a few side-notes:
gsoninstances thread-safe , can created once per whole application (and fine pass single instance components).- your
mymodelserializercan improved: should not creategsoninstance there since deserializers boundgsoninstance configuration, have delegate serialization via given contextcontext.serialize(mymodel.mitems, itemstype),itemstypenew typetoken<list<string>>() {}.gettype().
Comments
Post a Comment