How to deserialize a blank JSON string value to null for java.lang.String?
Asked Answered
P

5

35

I am trying a simple JSON to de-serialize in to java object. I am however, getting empty String values for java.lang.String property values. In rest of the properties, blank values are converting to null values(which is what I want).

My JSON and related Java class are listed below.

JSON string:

{
  "eventId" : 1,
  "title" : "sample event",
  "location" : "" 
}

EventBean class POJO:

public class EventBean {

    public Long eventId;
    public String title;
    public String location;

}

My main class code:

ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

try {
    File file = new   File(JsonTest.class.getClassLoader().getResource("event.txt").getFile());

    JsonNode root = mapper.readTree(file);
    // find out the applicationId

    EventBean e = mapper.treeToValue(root, EventBean.class);
    System.out.println("It is " + e.location);
}

I was expecting print "It is null". Instead, I am getting "It is ". Obviously, Jackson is not treating blank String values as NULL while converting to my String object type.

I read somewhere that it is expected. However, this is something I want to avoid for java.lang.String too. Is there a simple way?

Predestinarian answered 15/6, 2015 at 9:42 Comment(0)
L
35

Jackson will give you null for other objects, but for String it will give empty String.

But you can use a Custom JsonDeserializer to do this:

class CustomDeserializer extends JsonDeserializer<String> {

    @Override
    public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.readValueAsTree();
        if (node.asText().isEmpty()) {
            return null;
        }
        return node.toString();
    }

}

In class you have to use it for location field:

class EventBean {
    public Long eventId;
    public String title;

    @JsonDeserialize(using = CustomDeserializer.class)
    public String location;
}
Letdown answered 15/6, 2015 at 10:5 Comment(7)
This worked for me too, but using readValueAsTree() wrapped the string in extra quotes. So to avoid it I used instead jsonParser.readValueAs(String.class);Crowns
@Crowns extra quotes issue could be resolved by "return node.asText();"Watchful
Can we apply the JsonDeserialize annotation to class level also , so that all the string attributes with empty string under that will convert to null ?Alamein
@AnsarSamad Did you have an answer to your question? I would need to understand if it can be inserted at the class levelEberta
@Eberta yes it also works on the class level for all String fields.Pompidou
@Crowns yes this works, but only if this deserializer is never globally registered as a String deserializer via modules (see other answers below). Then you would end up with an infinite loop, so beware.Pompidou
@SachinGupta your code contains a small error; the final return statement should also use node.asText() so you don't return the double quotes. Please update your answer, i've tried to improve it with an edit but the reviewers rejected it.Pompidou
A
23

It is possible to define a custom deserializer for the String type, overriding the standard String deserializer:

this.mapper = new ObjectMapper();

SimpleModule module = new SimpleModule();

module.addDeserializer(String.class, new StdDeserializer<String>(String.class) {

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String result = StringDeserializer.instance.deserialize(p, ctxt);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        return result;
    }
});

mapper.registerModule(module);

This way all String fields will behave the same way.

Arron answered 21/4, 2016 at 20:45 Comment(0)
P
10

You might first like to see if there has been any progress on the Github issue requesting this exact feature.

For those using Spring Boot: The answer from jgesser was the most helpful to me, but I spent a while trying to work out the best way to configure it in Spring Boot.

Actually, the documentation says:

Any beans of type com.fasterxml.jackson.databind.Module are automatically registered with the auto-configured Jackson2ObjectMapperBuilder and are applied to any ObjectMapper instances that it creates.

So here's jgesser's answer expanded into something you can copy-paste into a new class in a Spring Boot application

@Configuration
public class EmptyStringAsNullJacksonConfiguration {

  @Bean
  SimpleModule emptyStringAsNullModule() {
    SimpleModule module = new SimpleModule();

    module.addDeserializer(
        String.class,
        new StdDeserializer<String>(String.class) {

          @Override
          public String deserialize(JsonParser parser, DeserializationContext context)
              throws IOException {
            String result = StringDeserializer.instance.deserialize(parser, context);
            if (StringUtils.isEmpty(result)) {
              return null;
            }
            return result;
          }
        });

    return module;
  }
}
Pittance answered 7/12, 2018 at 8:21 Comment(1)
Alas, the issue you're referring to has been closed by (one of) the maintainer(s) due to seemingly apparent lack of interest...Pella
G
4

I could get this by following configuration.

final ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
Goodrow answered 21/8, 2020 at 14:34 Comment(1)
This doesn't work - that deserialization feature is intended just for empty strings as the whole JSON expression (indicated by that "NULL_OBJECT") - not for object attributes.Pandemonium
R
0

it is possible to use JsonCreator annotation. It worked for me

public class Foo {
private String field;

 @JsonCreator
 public Foo(
   @JsonProrerty("field") String field) {
     this.field = StringUtils.EMPTY.equals(field) ? null : field ;
}
}
Resonator answered 31/7, 2020 at 14:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.