如何使用moshi、Reformation和java处理包装数据?

如何使用moshi、Reformation和java处理包装数据?,java,android,retrofit,moshi,Java,Android,Retrofit,Moshi,我正在使用一个API,其中所有数据都包装在一个自定义对象中(见下文),因此我无法使用moshi将改装主体直接转换到我的模型。在这种情况下,与moshi合作的最佳方式是什么 #COLLECTIONS ENDPOINT { "status": 200, "data": [ { "id": 28122, "name": "Aband

我正在使用一个API,其中所有数据都包装在一个自定义对象中(见下文),因此我无法使用moshi将改装主体直接转换到我的模型。在这种情况下,与moshi合作的最佳方式是什么

#COLLECTIONS ENDPOINT

{
    "status": 200,
    "data": [
        {
            "id": 28122,
            "name": "Abandonei",
            "counts": {
                "books": 3
            }
        },
        {
            "id": 21091,
            "name": "Lendo",
            "counts": {
                "books": 6
            }
        },
    ],
    "errors": [],
    "pagination": {
        "after": 2,
        "hasNextPage": true
    }
}
所有api端点都使用相同的json结构,默认字段为:

{
    "status": 200,
    "data": [],
    "errors": [],
    "pagination": {
        "after": 1,
        "hasNextPage": true
    }
}
我的收藏模式:

public class BookCollection {
    public long id;
    public String name;
    public ArrayList<Book> books;

    public BookCollection(long id, String name) {
        this.id = id;
        this.name = name;
    }
}
公共类图书收藏{
公共长id;
公共字符串名称;
公共图书馆图书;
公共BookCollection(长id、字符串名称){
this.id=id;
this.name=名称;
}
}

您需要设置gson/moshi来使用您为json到对象映射创建的类。下面是这些java类的示例。您也可以在kotlin中使用数据类。对于moshi,您必须创建适配器来帮助实现json到对象的映射

publci class CollectionResponse {

    public int status;
    public List<BookCollection> data;
    public List<Error> errors;
    public Pagination pagination;
}

public class Pagination {
    public int after;
    public boolean hasNextPage;
}

public class BookCollection {
    public long id;
    public String name;
    public Count counts;
    
}

public Count {
    public int books;
}

public class Error {
    
}
publci类集合响应{
公众地位;
公开名单数据;
公开列表错误;
公共分页分页;
}
公共类分页{
公共int之后;
公共布尔值下一页;
}
公共类藏书{
公共长id;
公共字符串名称;
公众计数;
}
公众计数{
公共图书;
}
公共类错误{
}

您需要设置gson/moshi来使用您为json到对象映射创建的类。下面是这些java类的示例。您也可以在kotlin中使用数据类。对于moshi,您必须创建适配器来帮助实现json到对象的映射

publci class CollectionResponse {

    public int status;
    public List<BookCollection> data;
    public List<Error> errors;
    public Pagination pagination;
}

public class Pagination {
    public int after;
    public boolean hasNextPage;
}

public class BookCollection {
    public long id;
    public String name;
    public Count counts;
    
}

public Count {
    public int books;
}

public class Error {
    
}
publci类集合响应{
公众地位;
公开名单数据;
公开列表错误;
公共分页分页;
}
公共类分页{
公共int之后;
公共布尔值下一页;
}
公共类藏书{
公共长id;
公共字符串名称;
公众计数;
}
公众计数{
公共图书;
}
公共类错误{
}

为了避免为每个模型创建父类,我实现了一种使用接收泛型类型的类的方法

为了实现这一点,我将Moshi类更改为Gson

我的模型:

public class BookCollection {
    public long id;
    public String name;
    public ArrayList<Book> books;

    public BookCollection(long id, String name) {
        this.id = id;
        this.name = name;
    }
}
用法:

public interface NetAPI {
    @GET("me/collections")
    Call<ResponseBody> getCollections(@Header("Authorization") String auth);
}

public class CollectionViewModel extends ViewModel {
    private final MutableLiveData<List<Collection>> collections = new MutableLiveData<>();
    private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
    private final MutableLiveData<Boolean> collectionError = new MutableLiveData<>();

    private Call<ResponseBody> call;
    
    private void fetchCollections() {
        loading.setValue(true);
        call = Api.getInstance().getCollections(TOKEN);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    collectionError.setValue(false);
                    
                    //THE SECRET
                    Gson gson = new Gson();
                    ApiWrapper<List<Collection>> apiResponse = null;
                    apiResponse = gson.fromJson(response.body().string(), new TypeToken<ApiWrapper<List<Collection>>>(){}.getType());

                    collections.setValue(apiResponse.data);

                    loading.setValue(false);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(getClass().getSimpleName(), "Error loading data", t);
                collectionError.setValue(true);
                loading.setValue(false);
            }
        });
    }
}
公共接口NetAPI{ @获取(“我/收藏”) 调用getCollections(@Header(“Authorization”)字符串auth); } 公共类CollectionViewModel扩展了ViewModel{ private final MutableLiveData collections=新的MutableLiveData(); private final MutableLiveData loading=新的MutableLiveData(); 私有最终MutableLiveData collectionError=新的MutableLiveData(); 私人通话; 私有void fetchCollections(){ 加载。设置值(真); call=Api.getInstance().getCollections(令牌); call.enqueue(新回调(){ @凌驾 公共void onResponse(调用、响应){ 试一试{ collectionError.setValue(假); //秘密 Gson Gson=新的Gson(); apiResponse=null; apiResponse=gson.fromJson(response.body().string(),newTypeToken(){}.getType()); collections.setValue(apiResponse.data); 加载设置值(false); }捕获(IOE异常){ e、 printStackTrace(); } } @凌驾 失败时公共无效(调用调用,可丢弃的t){ Log.e(getClass().getSimpleName(),“加载数据时出错”,t); collectionError.setValue(真); 加载设置值(false); } }); } } 通过这种方式,我可以将我的ApiWrapper类重用到任何模型(书籍、用户、登录等)


谢谢。

为了避免为每个模型创建父类,我实现了一种使用接收泛型类型的类的方法

为了实现这一点,我将Moshi类更改为Gson

我的模型:

public class BookCollection {
    public long id;
    public String name;
    public ArrayList<Book> books;

    public BookCollection(long id, String name) {
        this.id = id;
        this.name = name;
    }
}
用法:

public interface NetAPI {
    @GET("me/collections")
    Call<ResponseBody> getCollections(@Header("Authorization") String auth);
}

public class CollectionViewModel extends ViewModel {
    private final MutableLiveData<List<Collection>> collections = new MutableLiveData<>();
    private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
    private final MutableLiveData<Boolean> collectionError = new MutableLiveData<>();

    private Call<ResponseBody> call;
    
    private void fetchCollections() {
        loading.setValue(true);
        call = Api.getInstance().getCollections(TOKEN);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    collectionError.setValue(false);
                    
                    //THE SECRET
                    Gson gson = new Gson();
                    ApiWrapper<List<Collection>> apiResponse = null;
                    apiResponse = gson.fromJson(response.body().string(), new TypeToken<ApiWrapper<List<Collection>>>(){}.getType());

                    collections.setValue(apiResponse.data);

                    loading.setValue(false);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(getClass().getSimpleName(), "Error loading data", t);
                collectionError.setValue(true);
                loading.setValue(false);
            }
        });
    }
}
公共接口NetAPI{ @获取(“我/收藏”) 调用getCollections(@Header(“Authorization”)字符串auth); } 公共类CollectionViewModel扩展了ViewModel{ private final MutableLiveData collections=新的MutableLiveData(); private final MutableLiveData loading=新的MutableLiveData(); 私有最终MutableLiveData collectionError=新的MutableLiveData(); 私人通话; 私有void fetchCollections(){ 加载。设置值(真); call=Api.getInstance().getCollections(令牌); call.enqueue(新回调(){ @凌驾 公共void onResponse(调用、响应){ 试一试{ collectionError.setValue(假); //秘密 Gson Gson=新的Gson(); apiResponse=null; apiResponse=gson.fromJson(response.body().string(),newTypeToken(){}.getType()); collections.setValue(apiResponse.data); 加载设置值(false); }捕获(IOE异常){ e、 printStackTrace(); } } @凌驾 失败时公共无效(调用调用,可丢弃的t){ Log.e(getClass().getSimpleName(),“加载数据时出错”,t); collectionError.setValue(真); 加载设置值(false); } }); } } 通过这种方式,我可以将我的ApiWrapper类重用到任何模型(书籍、用户、登录等)


谢谢。

您的型号现在有什么代码?您的moshi适配器应该能够处理此数据而不会出现任何问题。@RayHunter我添加了我在该请求中使用的模型,以及api在所有端点上返回的json示例。您的json需要与您的模型匹配。因此,与其说是布克科尔