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:
gson
instances thread-safe , can created once per whole application (and fine pass single instance components).- your
mymodelserializer
can improved: should not creategson
instance there since deserializers boundgson
instance configuration, have delegate serialization via given contextcontext.serialize(mymodel.mitems, itemstype)
,itemstype
new typetoken<list<string>>() {}.gettype()
.
Comments
Post a Comment