Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to process an invalid value with Jackson JSON processor?

Tags:

json

jackson

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 ?

like image 216
wang Avatar asked Mar 07 '26 14:03

wang


1 Answers

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.)

like image 156
Programmer Bruce Avatar answered Mar 09 '26 06:03

Programmer Bruce



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!