4

I'm using the Jackson ObjectMapper class like so:

objectMapper.treeToValue(jsonNode, MyClass.class)

where jsonNode is an instance of JsonNode.

When I call treeToValue(), I get a MismatchedInputException with the message

Cannot deserialize instance of com.example.MyField` out of START_OBJECT token

because MyField is defined as a String inside of MyClass, but it is a JSON object inside of the jsonNode variable. I am perfectly OK with jsonNode having a non-matching type for one of its fields, but I'd rather ObjectMapper just not try and serialize this field and ignore it instead of throwing the MismatchedInputException.

I've tried using

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

but this just ignores missing fields, it does not do anything to prevent the MismatchedInputException for an existing field.

user2121620
  • 678
  • 12
  • 28
  • I don't think you can ignore it functionality wise unless you don't require the field; in that case you *could* `catch` the `MismatchedInputException` and just do nothing. However, I'm not sure that's quite what you're wanting to accomplish. – Hazel へいぜる Oct 16 '18 at 14:10
  • @PerpetualJ Right, I still want all of the other fields to be serialized. It seems like if I catch the `MismatchedInputException` it will just skip the whole serialization process – user2121620 Oct 16 '18 at 14:13
  • see this question and some crafty answers: https://stackoverflow.com/questions/4783421/how-can-i-include-raw-json-in-an-object-using-jackson – diginoise Oct 16 '18 at 14:19
  • @user2121620 I believe it will terminate the serialization process if you catch an exception. – Hazel へいぜる Oct 16 '18 at 14:48

2 Answers2

1

In the post that diginoise referred, you should have a look at this response:

https://stackoverflow.com/a/40972234/9343066

0

You can recursively remove offending fields and try again. Here is what I came up with (can be simplified based on your logging and exception handling needs).

public class YourClass {

    private static final Logger LOGGER = Logger
            .getLogger(YourClass.class.getName());

    public final static ObjectMapper mapper = new ObjectMapper().configure(
            DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    public static <T> T toTypedObject(Class<T> type, JsonNode tree) {
        return toTypedObject(type, tree, true);
    }

    private static <T> T toTypedObject(Class<T> type, JsonNode tree,
            boolean topLevel) {

        T object;

        try {
            object = mapper.treeToValue(tree, type);
        } catch (MismatchedInputException e) {
            String originalTree = tree.toString();
            object = toTypedObject(type, tree, originalTree, e);
            if (topLevel) {
                LOGGER.log(Level.WARNING, "Failed to convert node tree to a "
                        + type.getSimpleName()
                        + " object without modifications: " + originalTree, e);
                LOGGER.log(Level.INFO,
                        "Modified node tree was successfully converted to a "
                                + type.getSimpleName() + " object: " + tree);
            }
        } catch (JsonProcessingException e) {
            throw new YourException("Failed to convert node tree to a "
                    + type.getSimpleName() + " object: " + tree, e);
        }

        return object;
    }

    private static <T> T toTypedObject(Class<T> type, JsonNode tree,
            String originalTree,
            MismatchedInputException mismatchedInputException) {

        T object;

        List<Reference> path = mismatchedInputException.getPath();
        if (path != null && !path.isEmpty()) {

            try {

                ObjectNode subNode = (ObjectNode) tree;
                for (int i = 0; i < path.size(); i++) {
                    String fieldName = path.get(i).getFieldName();
                    if (i + 1 < path.size()) {
                        subNode = (ObjectNode) tree.get(fieldName);
                    } else {
                        subNode.remove(fieldName);
                    }
                }
                object = toTypedObject(type, tree, false);

            } catch (Exception e) {
                throw new YourException("Failed to convert node tree to a "
                        + type.getSimpleName() + " object: " + originalTree,
                        mismatchedInputException);
            }

        } else {
            throw new YourException(
                    "Failed to convert node tree to a " + type.getSimpleName()
                            + " object: " + originalTree,
                    mismatchedInputException);
        }

        return object;
    }

}

Call with:

YourObject yourObject = YourClass.toTypedObject(YourObject.class, tree);
bosborn
  • 16