Как сказать Джексону не включать информацию о типе коллекции?

Я столкнулся с «проблемой полиморфной десериализации», поэтому я настраиваю jackson для добавления информации о типе для неконкретных классов в качестве свойства следующим образом:

ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
        .withFieldVisibility(JsonAutoDetect.Visibility.NONE)
        .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
        .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
        .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
        .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE))
mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_CONCRETE_AND_ARRAYS, "__class__")

Он работает хорошо, но для экземпляров коллекции (например, List) он создает двухэлементный массив, в первой позиции которого находится строка с информацией о типе коллекции (java.util.ArrayList).

Это влияет на структуру json, которую ожидает клиент (Javascript), поскольку там, где он ожидал массив, теперь есть массив с другим внутри него во второй позиции.

Я хочу, чтобы Джексон вставлял информацию о типе только для неконкретных типов, не относящихся к коллекции, поскольку самой структуре не нужен тип реализации коллекции, чтобы правильно десериализовать свойства коллекции.

Возможно ли это настраиваемым образом?


person MV Gagliotti    schedule 11.09.2014    source источник


Ответы (1)


Вы можете создать собственную версию ObjectMapper.DefaultTypeResolverBuilder и переопределить метод useForType().

Вот реализация метода по умолчанию:

    public boolean useForType(JavaType t)
    {
        switch (_appliesFor) {
        case NON_CONCRETE_AND_ARRAYS:
            while (t.isArrayType()) {
                t = t.getContentType();
            }
            // fall through
        case OBJECT_AND_NON_CONCRETE:
            return (t.getRawClass() == Object.class) || !t.isConcrete();
        case NON_FINAL:
            while (t.isArrayType()) {
                t = t.getContentType();
            }
            return !t.isFinal(); // includes Object.class
        default:
        //case JAVA_LANG_OBJECT:
            return (t.getRawClass() == Object.class);
        }
    }

В вашей версии просто добавьте это предварительное условие

if (t.isCollectionLikeType()) {
    return false;
}

чтобы указать Джексону пропускать типы, подобные коллекции, для вставки информации о типе.

И установите новый TypeResolverBuilder с помощью ObjectMapper.setDefaultTyping(myCustomTyper);

person scip    schedule 24.04.2015