如何使用 Jackson JSON 处理器处理无效值?

发布于 2024-11-19 17:40:19 字数 544 浏览 0 评论 0原文

我使用 Jackson 来处理 json。

现在,我面临一个问题。

我的 POJO :

class Person{
    public String name;
    public int age;
}

JSON 是

{"name":"Jackson","age":""}.

如果我编写这样的代码:

Person person = mapper.readValue("{\"name\":\"Jackson\",\"age\":\"\"}", Person.class);

抛出异常:

无法从字符串值“”构造 int 实例:不是有效的 int 值。

如果 JSON 为 "{\"name\":\"Jackson\",\"age\":null}",就可以了。

但现在,我不想修改 JSON。我该怎么办?

I use Jackson to proccess json.

Now, I face a proplem.

My POJO :

class Person{
    public String name;
    public int age;
}

And the JSON is

{"name":"Jackson","age":""}.

If I write the code like this:

Person person = mapper.readValue("{\"name\":\"Jackson\",\"age\":\"\"}", Person.class);

A Exception is thrown:

Can not construct instance of int from String value "": not a valid int value.

If the JSON is "{\"name\":\"Jackson\",\"age\":null}", it’s OK.

But now , I don’t want to modify the JSON. And how can I do ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

与他有关 2024-11-26 17:40:20

我建议在 http://jira.codehaus.org/browse/JACKSON 记录问题,请求这被认为是一个错误,或者添加了允许正确处理的功能。 (也许 DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT 也允许将空 JSON 字符串反序列化为默认原始值是合理的,因为这就是绑定到 Java 原语时处理 JSON null 值的方式。)(更新:我登录了issue 616 对此进行投票。如果您希望实现它,请投票。)

在 Jackson 得到如此增强之前,需要自定义反序列化处理来将 JSON 空字符串转换为默认原始值(或到任何需要的非字符串值)。下面是这样一个例子,幸运的是它很简单,因为反序列化为 int 的现有代码已经处理了一个空字符串,将其转换为 0。

import java.io.IOException;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.deser.StdDeserializer;
import org.codehaus.jackson.map.module.SimpleModule;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    // {"name":"Jackson","age":""}
    String json = "{\"name\":\"Jackson\",\"age\":\"\"}";

    SimpleModule module = new SimpleModule("EmptyJsonStringAsInt", Version.unknownVersion());
    module.addDeserializer(int.class, new EmptyJsonStringAsIntDeserializer(int.class));

    ObjectMapper mapper = new ObjectMapper().withModule(module);
    Person p = mapper.readValue(json, Person.class);
    System.out.println(mapper.writeValueAsString(p));
    // {"name":"Jackson","age":0}
  }
}

class Person
{
  public String name;
  public int age;
}

class EmptyJsonStringAsIntDeserializer extends StdDeserializer<Integer>
{
  protected EmptyJsonStringAsIntDeserializer(Class<?> vc)
  {
    super(vc);
  }

  @Override
  public Integer deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException
  {
    return super._parseIntPrimitive(jp, ctxt);
  }
}

(另外,请注意,如果目标类型是 Integer 而不是 int,那么该字段将填充一个空值(这不是想要的)。为此,我记录了 问题 617,请求反序列化配置,以在绑定到原始包装类型字段时自动从 JSON null 值设置原始默认值,换句话说,当从 JSON null 反序列化时。 value 为 Integer 字段,目标字段将设置为 Integer.valueOf(0) 而不是 null。)

I recommend logging an issue at http://jira.codehaus.org/browse/JACKSON, requesting that this be considered a bug, or that a feature to allow proper handling is added. (Maybe it's reasonable that DeserializationConfig.Feature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT would also allow deserialization of empty JSON strings to default primitive values, since that's how JSON null values are otherwise handled, when bound to Java primitives.) (Update: I logged issue 616 for this. Vote for it if you want it implemented.)

Until Jackson is so enhanced, custom deserialization processing would be necessary to transform a JSON empty string to a default primitive value (or to whatever non-string value is wanted). Following is such an example, which is fortunately simple, since the existing code to deserialize to an int already handles an empty string, turning it into 0.

import java.io.IOException;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.deser.StdDeserializer;
import org.codehaus.jackson.map.module.SimpleModule;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    // {"name":"Jackson","age":""}
    String json = "{\"name\":\"Jackson\",\"age\":\"\"}";

    SimpleModule module = new SimpleModule("EmptyJsonStringAsInt", Version.unknownVersion());
    module.addDeserializer(int.class, new EmptyJsonStringAsIntDeserializer(int.class));

    ObjectMapper mapper = new ObjectMapper().withModule(module);
    Person p = mapper.readValue(json, Person.class);
    System.out.println(mapper.writeValueAsString(p));
    // {"name":"Jackson","age":0}
  }
}

class Person
{
  public String name;
  public int age;
}

class EmptyJsonStringAsIntDeserializer extends StdDeserializer<Integer>
{
  protected EmptyJsonStringAsIntDeserializer(Class<?> vc)
  {
    super(vc);
  }

  @Override
  public Integer deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException
  {
    return super._parseIntPrimitive(jp, ctxt);
  }
}

(Also, note that if the target type were Integer instead of int, then the field would be populated with a null value (not that that's what's wanted). For this, I logged issue 617, to request a deserialization configuration to automatically set the primitive default value from a JSON null value, when binding to a primitive wrapper type field. In other words, when deserializing from a JSON null value to an Integer field, the target field would be set to Integer.valueOf(0) instead of null.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文