Делегат Джексона Десериализатора следующему применимому десериализатору - PullRequest
0 голосов
/ 24 октября 2018

У меня есть внешний сервис, который я использую для запроса некоторых данных.Данные будут в одном из двух форматов (первый из которых является «устаревшим», но его необходимо поддерживать):

{
    "foo": "John Smith"
}

или

{
    "foo": {
        "name": "John Smith",
        "bar": "baz"
    }
}

, который я хочусопоставить со следующим POJO:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Outer {

    private Foo foo;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Foo {

        String name;
        String bar;

    }

}

Данные во втором формате (foo - это объект) должны быть десериализованы, как и любой другой POJO, но данные в первом формате (foo - это строка).), чтобы превратить его в экземпляр Foo, я хочу позвонить new Foo(<foo>, null).Для этого я создал собственный десериализатор (@JsonComponent означает, что этот десериализатор будет зарегистрирован с помощью своего рода глобального ObjectMapper к весне через интерфейс Jackson Module):

@JsonComponent
public class FooDeserializer extends JsonDeserializer<Outer.Foo> {

    @Override
    public Outer.Foo deserialize(JsonParser parser, DeserializationContext context)
            throws IOException {
        JsonNode node = parser.getCodec().readTree(parser);
        if (node.isTextual()) {
            return new Foo(node.asText(), null);
        }
        return <delegate to next applicable deserializer>;
    }

}

I 'У меня возникли проблемы с выяснением того, как выполнить часть «делегировать следующему применимому десериализатору», поскольку каждое решение, которое я пробовал (например, parser.getCodec().treeToValue(node, Outer.Foo.class)), заканчивается тем, что снова использует тот же пользовательский десериализатор, вызывая бесконечную рекурсию.Это вообще возможно?

1 Ответ

0 голосов
/ 31 октября 2018

Ответ кредитору Шуммару: Как вызвать десериализатор по умолчанию из пользовательского десериализатора в Джексоне .После приведенного выше ответа необходимо удалить аннотацию
1. @JsonComponent из настраиваемого сериализатора, поскольку нам необходимо создать настраиваемый сериализатор с использованием сериализатора по умолчанию, и это не поддерживается @JsonComponent.
2. РегистрацияSimpleModule до ObjectMapper с BeanDeserializerModifier и измените сериализатор с помощью нашего пользовательского сериализатора, созданного с помощью сериализатора по умолчанию.
3. В методе serialize пользовательского сериализатора обработайтеособый случай и делегировать сериализацию сериализатору по умолчанию для обычного случая.

Следующий код демонстрирует, как реализовать вышеуказанные пункты.

Основной класс

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class DelegateDeserializer {
    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {

        ObjectMapper mapper = new ObjectMapper();

        SimpleModule simpleModule = new SimpleModule();

        simpleModule.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc,
                    JsonDeserializer<?> deserializer) {
                if (Outer.Foo.class.isAssignableFrom(beanDesc.getBeanClass())) {
                    return new FooDeserializer(deserializer, beanDesc.getBeanClass());
                }
                return deserializer;
            }
        });

        mapper.registerModule(simpleModule);

        Outer outer1 = mapper.readValue(getType1Json(), Outer.class);
        Outer outer2 = mapper.readValue(getType2Json(), Outer.class);
        System.out.println("deserialize json with object structure:");
        System.out.println(outer1.getFoo().getName());
        System.out.println(outer1.getFoo().getBar());
        System.out.println("deserialize json with string field only:");
        System.out.println(outer2.getFoo().getName());
        System.out.println(outer2.getFoo().getBar());
    }

    private static String getType1Json() {

        return "  {                                                                        "
                + "  \"foo\": {                                                            "
                + "     \"name\": \"John Smith\",                                          "
                + "    \"bar\": \"baz\"                                                    "
                + "   }                                                                    "
                + "}                                                                       ";

    }

    private static String getType2Json() {

        return "  {                                                                        "
                + "  \"foo\": \"John Smith\"                                               "
                + "}                                                                       ";

    }
}

Класс FooDeserializer

import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import jackson.Outer.Foo;

public class FooDeserializer extends StdDeserializer<Outer.Foo> implements ResolvableDeserializer {

    private static final long serialVersionUID = 1L;
    private final JsonDeserializer<?> defaultDeserializer;

    public FooDeserializer(JsonDeserializer<?> defaultDeserializer, Class<?> clazz) {
        super(clazz);
        this.defaultDeserializer = defaultDeserializer;
    }

    @Override
    public Outer.Foo deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        if (parser.getCurrentToken() == JsonToken.VALUE_STRING) {
            JsonNode node = parser.getCodec().readTree(parser);
            if (node.isTextual()) {
                return new Foo(node.asText(), null);
            }
        }

        return (Foo) defaultDeserializer.deserialize(parser, context);
    }

    @Override
    public void resolve(DeserializationContext ctxt) throws JsonMappingException {
        ((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
    }

}

Внешний класс

 public class Outer {
    private Foo foo;

    public Foo getFoo() {
        return foo;
    }

    public void setFoo(Foo foo) {
        this.foo = foo;
    }

    public static class Foo {
        private String bar;
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getBar() {
            return bar;
        }

        public void setBar(String bar) {
            this.bar = bar;
        }

        public Foo() {
        }

        public Foo(String name, String bar) {
            this.name = name;
            this.bar = bar;
        }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...