Jackson - 将内部对象列表反序列化为更高级别的列表

2024-02-13

使用 Spring Boot 和 Jackson,如何将包装/内部列表直接反序列化为外层列表?

例如,我有:

{
    "transaction": {
    "items": {
        "item": [
            {
                "itemNumber": "193487654",
                "itemDescription": "Widget",
                "itemPrice": "599.00",
                "itemQuantity": "1",
                "itemBrandName": "ACME",
                "itemCategory": "Electronics",
                "itemTax": "12.95"
            },
            {
                "itemNumber": "193487654",
                "itemDescription": "Widget",
                "itemPrice": "599.00",
                "itemQuantity": "1",
                "itemBrandName": "ACME",
                "itemCategory": "Electronics",
                "itemTax": "12.95"
            }
        ]
    },
    ...
    }
}

在 JSON 中,item是下面的一个列表items;但我想将其解析为名为的列表items,直接在transaction,而不是定义 DTOItems其中包含一个名为的列表item.

这可能吗?如何定义这个DTOItem?

public class TrasactionDTO {
    private List<Item> items;
    ...
}

public class Item {

}

这个问题类似,但没有解决问题。使用 Jackson 反序列化包装列表 https://stackoverflow.com/questions/27699538/deserialize-wrapped-list-using-jackson


我们需要实现自定义解串器。因为我们想跳过一个内部字段,所以我们的实现应该:

  1. {- 跳过起始对象
  2. "any_field_name"- 跳过任何字段名称。我们假设我们只有一个内部场。
  3. [{}, ..., {}]- 使用默认解串器List.
  4. }- 跳过结束对象

使用上述概念实现应该很容易:

public class InnerListDeserializer extends JsonDeserializer<List> implements ContextualDeserializer {

    private final JavaType propertyType;

    public InnerListDeserializer() {
        this(null);
    }

    public InnerListDeserializer(JavaType propertyType) {
        this.propertyType = propertyType;
    }

    @Override
    public List deserialize(JsonParser p, DeserializationContext context) throws IOException {
        p.nextToken(); // SKIP START_OBJECT
        p.nextToken(); // SKIP any FIELD_NAME

        List list = context.readValue(p, propertyType);

        p.nextToken(); // SKIP END_OBJECT

        return list;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext context, BeanProperty property) {
        return new InnerListDeserializer(property.getType());
    }
}

假设我们有JSON有效负载如下:

{
  "transaction": {
    "items": {
      "item": [
        {
          "itemNumber": "193487654",
          "itemDescription": "Widget",
          "itemPrice": "599.00",
          "itemQuantity": "1",
          "itemBrandName": "ACME",
          "itemCategory": "Electronics",
          "itemTax": "12.95"
        },
        {
          "itemNumber": "193487654",
          "itemDescription": "Widget",
          "itemPrice": "599.00",
          "itemQuantity": "1",
          "itemBrandName": "ACME",
          "itemCategory": "Electronics",
          "itemTax": "12.95"
        }
      ]
    },
    "name": "Pickle Rick"
  }
}

Above JSON我们可以映射到下面POJO课程:

@JsonRootName("transaction")
public class Transaction {

    private String name;
    private List<Item> items;

    @JsonDeserialize(using = InnerListDeserializer.class)
    public List<Item> getItems() {
        return items;
    }

    // getters, setters, toString
}

public class Item {

    private String itemNumber;

    // getters, setters, toString
}

为了证明它适用于许多不同的模型,让我们再介绍一个JSON有效负载:

{
  "product": {
    "products": {
      "innerArray": [
        {
          "id": "1234"
        }
      ]
    }
  }
}

还有两个POJO课程:

@JsonRootName("product")
class Product {

    private List<ProductItem> products;

    @JsonDeserialize(using = InnerListDeserializer.class)
    public List<ProductItem> getProducts() {
        return products;
    }

    // getters, setters, toString
}

class ProductItem {

    private String id;

    // getters, setters, toString
}

现在我们可以测试我们的解决方案:

import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class JSoupTest {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        File jsonFile = new File("Path to 1-st JSON").getAbsoluteFile();
        File jsonFile1 = new File("Path to 2-nd JSON").getAbsoluteFile();

        System.out.println(mapper.readValue(jsonFile, Transaction.class));
        System.out.println(mapper.readValue(jsonFile1, Product.class));
    }
}

上面的例子打印:

Transaction{items=[Item{itemNumber=193487654}, Item{itemNumber=193487654}], name='Pickle Rick'}
Product{products=[ProductItem{id='1234'}]}

欲了解更多信息,请阅读:

  1. 自定义 Jackson 解串器获取当前字段类的访问权限 https://stackoverflow.com/questions/8944086/custom-jackson-deserializer-getting-access-to-current-field-class
  2. Jackson 中的自定义反序列化入门 https://www.baeldung.com/jackson-deserialization
  3. 杰克逊例外——问题和解决方案 https://www.baeldung.com/jackson-exception
  4. 杰克逊 UNWRAP_ROOT_VALUE https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/DeserializationFeature.html#UNWRAP_ROOT_VALUE
  5. 在 Spring 中配置 ObjectMapper https://stackoverflow.com/questions/7854030/configuring-objectmapper-in-spring
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jackson - 将内部对象列表反序列化为更高级别的列表 的相关文章

随机推荐

  • LINQ 选择项的 Lambda 表达式

    我有这个代码 var list db Projects Where item gt item Loc IN Select p gt new id p Id title p Title pc p PostalCode 项目表有很多列 我需要动
  • 如何将索引像素格式图像转换为 32 位图像?

    我获取了一个图像并尝试使用 Graphics FromImage image 加载到图形对象中 但是如果图像具有索引像素格式 则会引发异常 有没有办法安全地转换索引图像 Update 感谢 Joe 提供的提示 将旧图像绘制在新图像上 而不是
  • 如何将 gsutil 与多个帐户一起使用?

    我经常使用至少两个帐户的 Google Cloud Storage 电子邮件受保护 cdn cgi l email protection and 电子邮件受保护 cdn cgi l email protection 我用了gsutil co
  • 如何从打字稿访问垫菜单触发器

    我有以下 html
  • 如何以编程方式打开 Android Q 中的“设置”面板?

    As per 安卓Q新功能 有一个内联设置面板显示关键连接设置 使用户可以修改不同的连接设置 例如飞行模式 wifi 音量 NFC 和互联网连接 我怎样才能打开它以编程方式设置面板从我的应用程序 就像下面的屏幕截图一样 使用 Android
  • sum 函数如何在 python 中与 for 循环一起工作[重复]

    这个问题在这里已经有答案了 我在python中使用sum函数 我很清楚它的一般结构sum 可迭代 开始 但我无法理解以下代码背后的逻辑 test sum 5 for i in range 5 print output test 输出 25
  • Android:addTextChangedListener 无法正常工作

    我想对用户在其中输入的内容做出反应EditText所以我用了addTextChangedListener方法 当用户输入单个字符时 代码为onTextChanged正在运行 一切正常 例如 如果用户输入 a 那么onTextChanged将
  • ggplot2 以轴单位指定点大小

    我想从一个简单的数据集中绘制一个矩形内有大点的图 我想在不同方面显示可能有多个结果 问题是矩形的大小 使用geom rect 以轴单位定义 而size的论证geom point是在其他一些单位 因此 矩形上的点的相对大小根据面的数量而变化
  • 浏览器后退按钮处理

    我正在尝试处理浏览器后退按钮事件 但找不到任何解决方案 我想询问用户是否使用 确认框 单击浏览器后退按钮 如果他选择 确定 我必须允许后退按钮操作 否则我必须停止后退按钮操作 任何人都可以帮助我实现这一点 如果按下后退按钮 则警告 确认用户
  • 在 XElement.Load 上保留 \r\n

    有没有办法可以在 XElement Load 上保留 r n TextReader reader new StringReader rawInputString rawInputString is just text in html for
  • 关于清单中的全屏和无标题栏

    我想将我的应用程序设置为全屏视图 我想到将其设置在个人活动中使用FullScreen and NoTitlebar 但我想在整个应用程序的清单 XML 文件中设置它 而不是每个活动 这可能吗 帮助我 谢谢 要将您的应用程序或任何单独的活动显
  • 如何通过单击 ASP.NET 中的图像按钮来传输 zip 文件?

    我的问题 当用户单击 aspx 页面上的图像按钮时 代码隐藏会创建一个 zip 文件 然后我尝试将该 zip 文件流式传输给用户 为了流式传输文件 我使用以下代码 FileInfo toDownload new FileInfo fullF
  • C# 8 switch 表达式不够“智能”

    这段代码很简单 只是一个普通的开关 bool isSomething strSomething switch I gt true D gt false gt null 但是 编译器给了我以下错误 CS0037 无法将 null 转换为 bo
  • python中的嵌套正则表达式

    在 Perl 中我可以这样做 number qr zero one two three four five six seven eight nine ix foo qr quantity s number ix 我的实际正则表达式有很多行
  • 如何在浏览器中调试angularjs的$rootScope对象

    当 AngularJS 应用程序加载到浏览器中时 有没有办法对其进行调试 IE 我希望得到 rootScope我当前的应用程序 我该怎么做呢 巴塔朗 1 另外 您可以通过从控制台执行以下命令来获取 DOM 中任何元素的范围 angular
  • 根据列表框尺寸调整列表框内容的大小

    我正在尝试根据列表框本身调整列表框内容的大小 这是在 WPF 中完成的 关于这如何可能的任何想法 我认为当您说 调整大小 时 您的意思是您想要在两个方向上拉伸项目 要采用默认的列表框并水平拉伸项目 您需要做的是
  • C++ 求两个向量之间的差异

    假设你有 2 个向量 vector
  • 如何在 Eclipse 中找到可重写的方法

    public class test2 extends ListActivity 例如 我想找到 ListActivity 中可以重写的方法是什么 在 eclipse 中找到这个的快捷键是什么 如何通过 eclipse intellisens
  • 如何将 fancybox 绑定到动态添加的元素?

    我使用 jquery fancybox 1 3 4 作为弹出表单 但我发现 fancybox 无法绑定到动态添加的元素 例如 当我向当前文档添加 html 元素时 像这样 首先我使用 jquery 将一个元素附加到主体 document b
  • Jackson - 将内部对象列表反序列化为更高级别的列表

    使用 Spring Boot 和 Jackson 如何将包装 内部列表直接反序列化为外层列表 例如 我有 transaction items item itemNumber 193487654 itemDescription Widget