2

I am trying to extract attributes from a json sting in Java and I am writing a JsonDeseriizer to do it.
My attempt is shown below:

public class testJacksonSimple {
    @JsonDeserialize(using = ItemDeserializerJson.class)
    public static class Item {
        public int id;
        public String itemName;

        public Item(){};
        public Item(int id, String itemName) {
            this.id = id;
            this.itemName = itemName;
        }

        public void setId(int id) {
            this.id = id;
        }

        public int getId() {
            return id;
        }
    }

    public static class ItemDeserializerJson extends JsonDeserializer<Item> {

        ObjectReader reader = new ObjectMapper().reader();

        @Override
        public Item deserialize(JsonParser jp, DeserializationContext context) throws IOException {
            if(jp.currentToken() != JsonToken.VALUE_NULL) {
                return reader.readValue(jp, Item.class);
            } else {
                return null;
            }
        }
    }
}

This is my test case:

public class test {
    public static void main(String[] args){
        ObjectMapper mapper = new ObjectMapper();
        String json = "{\n" +
                "    \"id\": 1,\n" +
                "    \"itemName\": \"theItem\"\n" +
                "}";
        System.out.println(json);
        testJacksonSimple.Item itemWithOwner = null;
        try {
            itemWithOwner = new ObjectMapper().readValue(json, testJacksonSimple.Item.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(itemWithOwner.id);
        System.out.println(itemWithOwner.itemName);
    }
}

I got the error:

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.reflect.Method.getParameterTypes(Method.java:264)
    at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:59)
    at com.sun.proxy.$Proxy2.annotationType(Unknown Source)
    at com.fasterxml.jackson.databind.introspect.AnnotationMap._add(AnnotationMap.java:135)
    at com.fasterxml.jackson.databind.introspect.AnnotationMap.addIfNotPresent(AnnotationMap.java:101)
    at com.fasterxml.jackson.databind.introspect.AnnotatedClass._addAnnotationsIfNotPresent(AnnotatedClass.java:1061)
    at com.fasterxml.jackson.databind.introspect.AnnotatedClass._resolveClassAnnotations(AnnotatedClass.java:399)
    at com.fasterxml.jackson.databind.introspect.AnnotatedClass._classAnnotations(AnnotatedClass.java:376)
    at com.fasterxml.jackson.databind.introspect.AnnotatedClass.getAnnotation(AnnotatedClass.java:248)
    at com.fasterxml.jackson.databind.AnnotationIntrospector._findAnnotation(AnnotationIntrospector.java:1436)
    at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector.findAutoDetectVisibility(JacksonAnnotationIntrospector.java:349)
    at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.<init>(POJOPropertiesCollector.java:129)

Just do not understand why I got error stackoverflow. I can get correct result without using custom JSONDeserializer, but I want to test it. Any help is appreciated.

Frank Kong
  • 1,010
  • 1
  • 20
  • 32

2 Answers2

4

You have created an infinite loop by calling the objectmapper and requesting it to deserialize your json from inside the custom deserializer. The object mapper is calling your custom deserializer and then your custom deserializer is calling the objectmapper. Hence the stackoverflow.

The following worked for me:

    public static class ItemDeserializerJson extends JsonDeserializer<Item> {

    @Override
    public Item deserialize(JsonParser jp, DeserializationContext context) throws IOException {

        JsonNode node = jp.getCodec().readTree(jp);
        int id = (Integer) (node.get("id")).numberValue();
        String itemName = node.get("itemName").asText();

        return new Item(id, itemName);
    }
}
Justin.Cooke
  • 387
  • 2
  • 15
-1

So basically reader.readValue(jp, Item.class); will call deserialize method recurrently. By the way please keep to naming conventions (class name should be UpperCamelCase): http://www.oracle.com/technetwork/java/javase/overview/codeconventions-135099.html

standy
  • 398
  • 1
  • 3
  • 16
  • So how can I solve the problem "reader.readValue(jp, Item.class); will call deserialize method recurrently." – Frank Kong Jul 31 '18 at 14:11
  • using google does not hurt: http://www.baeldung.com/jackson-deserialization – standy Jul 31 '18 at 14:16
  • Did you open that link? I just used that as my example. Std deserailizet instead of JsonDeserializer is used in the example. – Frank Kong Jul 31 '18 at 14:28
  • 1
    Instead of suggesting to google, it would be nicer if you could provide more information about why this error happened at all. I don't think that you explained it with clarity in your answer. – Eirini Graonidou Jul 31 '18 at 14:38