Retrofit2 Handle condition when status code 200 but json structure different than datamodel class

后端 未结 5 449
-上瘾入骨i
-上瘾入骨i 2021-02-01 22:09

I\'m using Retrofit2 and RxJava2CallAdapterFactory.

The API I consume returns status code always as 200 and for success and response JSON string the JSON st

5条回答
  •  旧巷少年郎
    2021-02-01 23:08

    One possible solution is to make Gson fail on unknown properties. There seems to be an issue raised already(https://github.com/google/gson/issues/188). You can use the workaround provided in the issue page. So the steps are as follows:

    Add the workaround ValidatorAdapterFactory to the code base:

    public class ValidatorAdapterFactory implements TypeAdapterFactory {
    
    @Override
    public  TypeAdapter create(Gson gson, TypeToken type) {
        // If the type adapter is a reflective type adapter, we want to modify the implementation using reflection. The
        // trick is to replace the Map object used to lookup the property name. Instead of returning null if the
        // property is not found, we throw a Json exception to terminate the deserialization.
        TypeAdapter delegate = gson.getDelegateAdapter(this, type);
    
        // Check if the type adapter is a reflective, cause this solution only work for reflection.
        if (delegate instanceof ReflectiveTypeAdapterFactory.Adapter) {
    
            try {
                // Get reference to the existing boundFields.
                Field f = delegate.getClass().getDeclaredField("boundFields");
                f.setAccessible(true);
                Map boundFields = (Map) f.get(delegate);
    
                // Then replace it with our implementation throwing exception if the value is null.
                boundFields = new LinkedHashMap(boundFields) {
    
                    @Override
                    public Object get(Object key) {
    
                        Object value = super.get(key);
                        if (value == null) {
                            throw new JsonParseException("invalid property name: " + key);
                        }
                        return value;
    
                    }
    
                };
                // Finally, push our custom map back using reflection.
                f.set(delegate, boundFields);
    
            } catch (Exception e) {
                // Should never happen if the implementation doesn't change.
                throw new IllegalStateException(e);
            }
    
        }
        return delegate;
        }
    
    }
    

    Build a Gson object with this TypeAdaptorFactory:

    Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ValidatorAdapterFactory()).create()
    

    And then use this gson instance in GsonConverterFactory like below:

    apiClient = new Retrofit.Builder()
                    .baseUrl(url)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(gson)) //Made change here
                    .client(httpClient)
                    .build();
    

    This should throw an error if the unmarshalling step finds an unknown property, in this case the error response structure.

提交回复
热议问题