【问题标题】:Mapping a JSONObject to a List with Flexjson in Java / Android在 Java / Android 中使用 Flexjson 将 JSONObject 映射到列表
【发布时间】:2012-10-21 00:30:34
【问题描述】:

我目前正在尝试使用 Flexjson 反序列化 JSON 字符串并将其映射到我的对象模型 安卓应用。该应用程序是一种具有多个供应商的库,可以有一些目录和更多目录 和其中的文件。 json 是从我没有影响的 Web 服务中获取的,看起来像这样:

{
    "library":{
        "vendor":[
            {
                "id":146,
                "title":"Vendor1",
                "catalog":[
                     {
                        "id":847,
                        "document":[
                            {
                                "id":1628,
                                "title":"Document",
                ...
                            },
                            {
                ...
                            }
                        ],
                        "title":"Catalog ",
                    },
                {
                ...
                }
              ]
            },
            {
            ...
            }
        ]
    }
}

因此,每个供应商、目录、文档都由 JSONObject 表示,所有子目录和文档都在 JSONArray 中。 到目前为止,Flexjson 和以下反序列化代码一切正常:

LibraryResponse response = new JSONDeserializer<LibraryResponse>()
                    .use(Timestamp.class, new TimestampObjectFactory())
                    .deserialize(getLocalLibrary(), LibraryResponse.class);
return response.library;

我确实有一个具有List&lt;Vendor&gt; 的库对象。每个供应商都有一个List&lt;Catalog&gt; 和一个List&lt;Document&gt;

但不幸的是,如果目录仅包含单个文档,则 Web 服务会将 JSONArrays 绑定到简单的 JSONObjects 或者一个目录只包含一个目录。所以这种情况下的 json 看起来像这样:

"document":
    {
        "id":1628, 
        "title":"Document",
        ...
    }

现在 Flexjson 不知道如何反序列化,我最终得到一个 library.vendorX.getDocument() 是 List&lt;HashMap&gt; 而不是 List&lt;Document&gt;。 一个想法是明确告诉 Flexjson 如何处理这种情况,但我不知道从哪里开始。另一种方法是手动解析初始 json 并将此类 JSONObjects 替换为适当的 JSONArray。但我认为这种方式不太好走,因为图书馆可能很深。

希望您能在这里提供一些指导。

【问题讨论】:

    标签: java android json deserialization flexjson


    【解决方案1】:

    哎呀,这是一些粗糙的 json 映射。哪个后端编码器做到了?! #NotHelping。

    从代码来看,Flexjson 被编码为开箱即用地处理这个问题。但看起来它没有将输入信息传递给绑定,所以它不知道它绑定到什么类型,所以它只返回一个 Map。这是一个应该修复的错误好消息是有解决办法

    无论如何,我能想到的最简单的事情就是在该列表上安装一个 ObjectFactory。然后您可以检查并查看在反序列化流时是否获得 Map 或 List 。然后您可以将其包装在一个列表中并将其发送到适当的解码器。比如:

    LibraryResponse response = new JSONDeserializer<LibraryResponse>()
                    .use(Timestamp.class, new TimestampObjectFactory())
                    .use("library.vendor.values.catalog.values.document", new ListDocumentFactory() )
                    .deserialize(getLocalLibrary(), LibraryResponse.class);
    

    然后

    public class ListDocumentFactory implements ObjectFactory {
    
         public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) {
             if( value instanceof Collection ) {
                 return context.bindIntoCollection((Collection)value, new ArrayList(), targetType);
             } else {
                 List collection = new ArrayList();
                 if( targetType instanceof ParameterizedType ) {
                     ParameterizedType ptype = (ParameterizedType) targetType;
                     collection.add( context.bind(value, ptype.getActualTypeArguments()[0]) );
                 } else {
                     collection.add( context.bind( value ) );
                     return collection;
                 }
             }
         }
    }
    

    我认为这大致可以解决该错误,但也应该可以解决您的问题。

    【讨论】:

    • 感谢您的回答!我想我让自己不清楚,我总是得到一个列表,但如果列表中只有一个文件我没有Documents,但HashMaps,所以List&lt;HashMap&gt;catalog.document 而不是List&lt;Document&gt; .哈希映射对象包含连接到文档的数据。对我来说似乎很奇怪。我想我需要一个工厂来决定我们是否已经有一个文档或者我们是否有一个HashMap。如果是后者,我会手动映射文档对象。不过,我的第一次尝试失败了。您认为这种方法可行吗?
    • 我看不到我的回答没有回答您的问题。我认为您获得 List 而不是 List 的原因是 Flexjson 中的一个错误。 JSONDeserializer 首先将 JSON 转换为简单的对象,如 List、Map、String、Number 和 Boolean。然后它使用一系列 ObjectFactory 将这些简单对象映射到您要映射到的实际对象中。所以 ObjectFactory 层是在我们拥有像 Document 这样的强类型对象之前。因此,您将像我展示的那样编写自己的 ObjectFactory,而不是使用默认实例。
    • 对不起,我想我误解了你。无论如何,在尝试编写代码时,我在ParameterizedType ptype = (ParameterizedType) targetType;java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 遇到异常。另一个问题:如果我指定要在library.vendor.values.catalog.values.document 上使用的工厂,它不会影响library.vendor.values.document 的其他级别吗?因为即使是供应商也可以有文件......是否可以指定要在 LibraryItem.class 上使用的工厂,这是所有其他工厂的超类?
    • 按对象路径指定只会将该 ObjectFactory 用于该路径(除非您使用通配符)。您可以按类设置 ObjectFactories,但在这种情况下,您需要在所有 List.class 上设置它。好消息是您可以在所有 List.class 上设置它,因为代码与 Document 的任何细节无关。如果您遇到异常,您是否在实例变量上使用泛型?例如列表?如果不是,那么 Flexjson 将不知道将 JSON 映射到列表中的对象类型。
    • List.class 上使用工厂终于成功了!非常感谢您的大力支持。 Flexjson 很棒,即使在与讨厌的后端开发人员打交道时也是如此;-)。
    猜你喜欢
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 2015-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多