2

I'm testing deserializing to a collection object when my JsonNode no value. I want the object to be equal to null.

This is what I'm trying:

public class ImmutableDiscoveredUrlDeserializer extends JsonDeserializer<ImmutableDiscoveredUrl> {
String parentUrl;
Double parentUrlSentiment;
Set<String> childUrls;
Boolean isParentVendorUrl;
Map<TagClassification, Set<String>> parentUrlArticleTags;

/*
 * (non-Javadoc)
 * @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
 */
@Override
public ImmutableDiscoveredUrl deserialize(JsonParser p, DeserializationContext ctx)
    throws IOException {

    JsonNode node = p.readValueAsTree();
    parentUrl = defaultIfNull(node.get("parentUrl").asText(), null);
    childUrls = defaultIfNull(parseChildUrls(node), emptySet());
    isParentVendorUrl = defaultIfNull(Boolean.valueOf(node.get("isParentVendorUrl").asText()), null);
    parentUrlArticleTags = defaultIfNull(parseArticleTags(node.get("parentUrlArticleTags")), emptyMap());

    return ImmutableDiscoveredUrl.discoveredUrl().parentUrl(parentUrl)
                .parentUrlSentiment(parentUrlSentiment).childUrls(childUrls)
            .isParentVendorUrl(isParentVendorUrl).parentUrlArticleTags(parentUrlArticleTags);
}

private Set<String> parseChildUrls(JsonNode node) throws IOException {
    ObjectMapper tagsMapper = new ObjectMapper();
    return tagsMapper.convertValue(node, new TypeReference<Set<String>>() {});
}

private Map<TagClassification, Set<String>> parseArticleTags(JsonNode node) throws IOException {
    ObjectMapper tagsMapper = new ObjectMapper();
    return tagsMapper.convertValue(node, new TypeReference<Set<String>>() {});
}

But I get a MismatchedInputException, stating that there's no content to map. How do I get the ObjectMapper to return a null?

CNDyson
  • 1,687
  • 7
  • 28
  • 63

2 Answers2

5

Since you already have a JsonNode you can use ObjectMapper#convertValue:

@Test
public void converts_null_to_null() throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    JsonNode jsonNode = mapper.readTree("{\"foo\":null}");
    JsonNode foo = jsonNode.get("foo");

    Set<String> result = mapper.convertValue(foo, new TypeReference<Set<String>>() {});

    assertNull(result);
}

Note that convertValue() will not work as intended if you pass in a plain Map. In your case you need to remove defaultIfNull and check for null yourself:

if (node.get("parentUrlArticleTags") !== null) {
    parentUrlArticleTags = parseArticleTags(node.get("parentUrlArticleTags"));
}
hzpz
  • 7,536
  • 1
  • 38
  • 44
  • Hmm, now I get this exception: java.lang.IllegalArgumentException: Cannot deserialize instance of java.util.HashSet out of START_OBJECT token at [Source: UNKNOWN; line: -1, column: -1] I DON'T get the same exception when I run your snippet, so I don't know what's wrong with my use case. – CNDyson Aug 04 '17 at 14:57
  • That's weird, the snippet runs fine for me, if I execute it as a JUnit test. Which version of Jackson are you using? – hzpz Aug 04 '17 at 15:03
  • I edited my comment to show that it did actually run for me, sorry. The only difference I can see is that I instantiate one ObjectMapper to read the tree, and another to get the node. Can that be my problem? – CNDyson Aug 04 '17 at 15:04
  • ACTUALLY, I use the JsonParser to read the tree - not the ObjectMapper at all. The parser comes as part of the signature to deserialize(). I'll edit my question to show the full class. – CNDyson Aug 04 '17 at 15:08
  • Hm, please post more code. You're obviously doing something different than me. – hzpz Aug 04 '17 at 15:11
  • Thank you. I was checking for null before, but was advised that I shouldn't need to. I guess I do. Appreciate your time! – CNDyson Aug 04 '17 at 15:23
0

In my case I had a little different issue, for getting

Cannot deserialize instance of `java.util.HashSet` out of START_OBJECT token
 at [Source: (String)"{"bbc":"firstbckt","ssg":{"751fad0":"751fad0","be0eb99":"be0eb99"}}"

and here was my POJO

import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("serial")
public class BulkUploadRsp implements Serializable {
    private String bbc;
    private Map<String, String> ssgs = Maps.newHashMap();
    //..
    public void setSsgs(Set<String> ssgs) {
        this.ssgs = ssgs.stream().collect(Collectors.toMap(ssg -> ssg, ssg -> ssg));
    }
}

Issue was: I had this util method which starts with set*. Renaming it to setSsgs(Set<String> ssgs) helped resolve the issue

Anand Rockzz
  • 6,072
  • 5
  • 64
  • 71