Retrofit Gson parsing an empty string

Source: Internet
Author: User

In the actual development project, the server often uses the empty string "" as the return result to represent the null value, but this will encounter the problem in the Gson, if this data type is not the string, Gson parsing will be an error
We want the program to automatically parse an empty string into a null value of the corresponding type, such as an integer that resolves to a 0,list type and resolves to an empty List

This problem can be said that I used Retrofit+gson since the biggest pit, so that I in the study of almost all to the source of the finished reading

One bizarre thing is that gson when parsing an empty string with an integer, the report is actually "Inavalid double" error
After research source found that Gson will first try to resolve to integer type, parsing failure will not report errors,
Continue to try to resolve to double type, and then fail to error, so got "Inavalid double"

Solution:
For the parsing of integer type, first write a parsing adapter, implement Jsonserializer, Jsondeserializer
Override parsing method, first attempt to parse with string type, if equal to empty string "", return 0 value
Otherwise try to parse with integer type, and catch number format exception to JSON parsing exception thrown

 Public  class integerdefault0adapter implements Jsonserializer<Integer  Jsondeserializer<Integer> {@Override PublicInteger Deserialize (jsonelement json, Type Typeoft, Jsondeserializationcontext context) Throws Jsonparseexception {Try{if(Json.getasstring (). Equals ("")){return 0; }        }Catch(ExceptionIgnore) {}Try{returnJson.getasint (); }Catch(NumberFormatException e) {Throw NewJsonsyntaxexception (e); }} @Override PublicJsonelement Serialize (Integer src, Type typeofsrc, Jsonserializationcontext context) {return NewJsonprimitive (SRC); }}

Then register the adapter to type integer and type int in the Gsonbuilder

publicstaticbuildGson() {       ifnull) {           new GsonBuilder()                   .setDateFormat("yyyy-MM-dd HH:mm:ss")                   new IntegerDefault0Adapter())                   .registerTypeAdapter(intnew IntegerDefault0Adapter())                   .create();       }       return gson;   }

Then replace the native with this custom Gson when building the retrofit.

Retrofit = new Retrofit.Builder()                .baseUrl"/")                //传入buildGson生成的自定义Gson                .addConverterFactory(ResponseConverterFactory.create(buildGson()))                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .client(mOkHttpClient)                .build();

This allows the Gson to parse an empty string to 0 when it encounters integer parsing.

Then I'm going to solve the list's parsing problem in the same way, but I didn't think it was that simple.

Because list is not a basic type like shaping, the list itself is a generic when parsing data.
I can't set the data type in the collection when I build it.

If the data type in the generic is indeterminate, the rewrite adapter will have to operate separately depending on the type encountered at run time, which is tantamount to gson the work.

After research source found that Gson treats list is not as a type to parse
Instead, it is initialized with a collectiontypeadapterfactory, which invokes the parser of the collection type when the data that encounters the Jsonarray type, and then fits the corresponding data type in the collection. In a word, it's complicated, and not how to expand.

After research I found the solution is:

By annotating the @jsonadapter you can specify the corresponding adapter, the priority is higher than the default collectiontypeadapterfactory, and the adapter passed through the Gsonbuilder.
Then copy the collectiontypeadapterfactory out and change a listtypeadapterfactory.

/** * List Resolution Class Adapter factory class * Must be annotated @jsonadapter way to take precedence over the default collectiontypeadapterfactory */ PublicFinalclassListtypeadapterfactory implements Typeadapterfactory { Public<T> typeadapter<t>Create(Gson Gson, typetoken<t> TypeToken)        {Type type = Typetoken.gettype (); class<? Super T> Rawtype = Typetoken.getrawtype ();if(! List.class.isAssignableFrom (Rawtype)) {return NULL;        } Type ElementType = $Gson $types.getcollectionelementtype (type, rawtype); typeadapter<?> elementtypeadapter = Gson.getadapter (TypeToken.Get(ElementType)); @SuppressWarnings ({"Unchecked","Rawtypes"})//Create () doesn ' t define a type parametertypeadapter<t> result =NewAdapter (Gson, ElementType, Elementtypeadapter);returnResult }Private StaticFinalclassAdapter<e> extends Typeadapter<list<e>> {PrivateFinal typeadapter<e> Elementtypeadapter; Public Adapter(Gson context, Type ElementType, typeadapter<e> elementtypeadapter) { This. Elementtypeadapter =NewTypeadapterruntimetypewrapper<e> (context, Elementtypeadapter, ElementType); }//Key section is here, overriding the parsing method         PublicList<e>Read(Jsonreaderinch) throws IOException {//null value returns null            if(inch. Peek () = = Jsontoken.null) {inch. Nextnull ();return NULL; }//Create a new empty listlist<e> list =NewArraylist<> ();Try{inch. Beginarray (); while(inch. Hasnext ()) {E instance = Elementtypeadapter.read (inch);                List.add (instance); }inch. Endarray ();//Normal parsing becomes list}Catch(IllegalStateException e) {//If it is an empty string, there will be a Begin_array error                //Attempt to parse into a string, if not an empty string, still throws an exception                //If it is an empty string, it does not throw an exception, which eventually returns an empty list                if(!"". Equals (inch. nextstring ())) {ThrowE }            }returnList } Public void Write(Jsonwriter out, list<e> List) throws IOException {if(List = =NULL) { out. Nullvalue ();return; } out. Beginarray (); for(E element:list) {Elementtypeadapter.write ( out, Element); } out. Endarray (); }    }}

The last is the model class inside the annotation designation

publicclass UserListModel{    @JsonAdapter(ListTypeAdapterFactory.class)    List<UserProfileModel> users;}

This allows the Gson to parse an empty string into an empty list.

Transferred from: http://blog.csdn.net/efan006/article/details/50544509

Retrofit Gson parsing an empty string

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.