【问题标题】:Jackson Unmarshalling not-provided valuesJackson Unmarshalling 未提供的值
【发布时间】:2016-03-01 18:17:06
【问题描述】:

我目前正在尝试实现一个 PATCH 端点,该端点应该只更改 JSON 帖子正文中实际提供的值。不幸的是,杰克逊似乎将未提供的值视为 NULL,因此重置了这些现有值。 下面的例子:

public class Item {

    @Id @GeneratedValue
    private Long id;

    private String name;

    //getters+setters
}

和相应的控制器:

@RequestMapping(value = /item/{id}, method = RequestMethod.PATCH)
public ResponseEntity<Item> patchItem(@PathVariable("id") Long itemId, @RequestBody Item item) {
    if (itemRepository.exists(itemId) && item.getId().equals(itemId)) {
        Item newItem = itemRepository.save(item);
        return new ResponseEntity<>(newItem, HttpStatus.OK);
    }
    throw new ResourceNotFoundException("could not find Item with id " + itemId);
} 

当我现在只使用提供的 ID 调用该端点时,我希望现有名称不为空:

PATCH to /item/1 with postbody { "id":1 }

应该会导致

{
   "id":1,
   "name":"value_before_patch"
}

而不是在{ "id":1 } 中(由于builder.serializationInclusion(JsonInclude.Include.NON_NULL);) 现在没有提供名称。

我需要如何配置 Jackson 来实现这一点?

【问题讨论】:

  • 您是否检查了控制器中的 Item 方法参数中是否存在该名称?
  • 您的意思是手动进行检查?例如,首先从数据库中加载现有实体,然后检查提供的实体是否设置了值,如果存在并且不同,然后更新值?然后我将如何 NULL 一个值(例如,如果我想取消链接)?这与对整个对象执行 PUT 是否或多或少相同?
  • 我的意思是缩小JSON转换和数据存储库之间的问题?哪个组件占用了“name”参数的值?
  • 该名称不是方法参数的一部分 - 在我的示例中它只是 id。这就是 PATCH 方法的全部思想:您只提供您实际想要更改的字段(在这种情况下,我的示例有点草率,因为我不希望更改 id,但为了简单起见......) .

标签: java json rest spring-boot jackson


【解决方案1】:

也许问题中有一些我不明白的地方,但是: 如果您在 JSON 中提供不完整的对象表示,则 java 中的结果字段将为空。怎么可能和那不一样?当您保存(不完整的)反序列化对象时,JSON 中未指定的字段将被取消。你对此无能为力。 您可以做的是检查您要保存的 java 对象上的每个字段,并将旧值放入每个空字段中。

附带说明一下,这就是(afaict)PATCH 不是通用服务的原因,即它很难实现,特别是如果您有复杂的对象。

编辑: 我不知道json-patch 提议的标准。这可能是您想要实现的目标的解决方案。我建议您查看this tutorial on how to integrate it with Jersey,甚至查看rfc (6902)。简而言之,json-patch 形式化了您如何发送命令 (patches) 以选择性地修改对象。一个例子如下:

给定一个 json 初始表示为的对象

{  
  "list" : [  
    "one",  
    "two"  
  ],  
  "message" : "message",  
  "title" : "title"  
}  

你可以用类似的 json 来修补它

[  
  {  
    "op" : "replace",  
    "path" : "/message",  
    "value" : "otherMessage"  
  },  
  {  
    "op" : "add",  
    "path" : "/list/-",  
    "value" : "three"  
  }  
]  

希望这能有所帮助。

【讨论】:

  • 我将如何取消设置我想要明确为空的值? (这与对整个对象执行 PUT 是否或多或少相同?)
  • 理论上你不能,即你无法区分你收到的 null 是未更新的字段还是无效的字段。这就是为什么更新操作通常使用 PUT 而不是 PATCH 实现的另一个原因。如果您想使用 PATCH,想到的解决方法是定义一个声明空对象的约定(例如,空字符串将是 "null")。这样你可以区分这两种情况,但它有很多缺点。
  • @francesco foresti 即:布尔值
猜你喜欢
  • 2020-10-05
  • 1970-01-01
  • 2015-06-13
  • 1970-01-01
  • 2022-10-07
  • 2018-05-30
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
相关资源
最近更新 更多