Search code examples
javajackson-databindjackson2

Custom Jackson deserialization - getting com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected end-of-input when binding data


I'm trying to write a custom deserializer for an Object that's type aware (TypeAwareObject in code below). I'm getting the following error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected end-of-input when binding data into TestMain$Value

FYI I'm using the lombok for boilerplate reduction (for autogenerating getters, setters, and constructors)

public class TestMain {

    public static void main(String[] args) throws IOException {
        final ObjectMapper mapper = new ObjectMapper();

        final String str = mapper
                .writeValueAsString(new TypeAwareObject(Value.class, new Value("test")));
        System.out.println(str);

        TypeAwareObject obj = mapper.readValue(str, TypeAwareObject.class);
        System.out.println(obj);
    }

    @lombok.Data
    public static class Value implements Serializable{
        private static final long serialVersionUID = 1L;
        private final String v;
    }

    @JsonDeserialize(using = TypeAwareObjectDeserializer.class)
    @lombok.Data
    @lombok.RequiredArgsConstructor
    public static class TypeAwareObject implements Serializable {
        private static final long serialVersionUID = 1L;
        private final Class<? extends Serializable> type;
        private final Serializable value;
    }

    public static class TypeAwareObjectDeserializer extends StdDeserializer<TypeAwareObject> {
        private static final long serialVersionUID = 1L;

        public TypeAwareObjectDeserializer() {
            super(TypeAwareObject.class);
        }

        @Override
        public TypeAwareObject deserialize(JsonParser jsonParser, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {

            final ObjectCodec objectCodec = jsonParser.getCodec();

            final JsonNode jsonNode = objectCodec.readTree(jsonParser);
            final String typeClassName = jsonNode.get("type").asText();
            try {

                @SuppressWarnings("unchecked")
                final Class<? extends Serializable> type = (Class<? extends Serializable>) Class.forName(typeClassName);

                final JsonNode valueNode = jsonNode.get("value");   
                final Serializable value = ctxt.readValue(valueNode.traverse(), type);

                return new TypeAwareObject(type, value);

            } catch (ClassNotFoundException typeNotFound) {             
                throw new JsonParseException(jsonParser, //
                        "Error in deserializing TypeAwareObject", //
                        typeNotFound);
            }
        }
    }

}

I get the following error below. I'm sure I'm missing something small but can't quite put my finger on it.. What am I doing wrong? :( Please help!!!

{"type":"TestMain$Value","value":{"v":"test"}}
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected end-of-input when binding data into `TestMain$Value`
 at [Source: (String)"{"type":"TestMain$Value","value":{"v":"test"}}"; line: 1, column: 46]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1139)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1093)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:198)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
    at com.fasterxml.jackson.databind.DeserializationContext.readValue(DeserializationContext.java:760)
    at com.fasterxml.jackson.databind.DeserializationContext.readValue(DeserializationContext.java:747)
    at TestMain$TypeAwareObjectDeserializer.deserialize(TestMain.java:67)
    at TestMain$TypeAwareObjectDeserializer.deserialize(TestMain.java:1)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
    at TestMain.main(TestMain.java:28)


Solution

  • so im not an expert on JsonParsing but i found the currentToken that the readValue is referenceing is initialized as null.

    some testing lead me to this create the parser and tell it to instantly go to the next Token (there might be a possiblity to initialize the parser with loading the first token but i dont know it).

    JsonParser parser = valueNode2.traverse();
    parser.nextToken();
    final Serializable value = ctxt.readValue(parser, type);