Есть ли способ определить целевой тип абстрактного объекта путем включения массива в Джексона? - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть следующий класс, который должен быть сериализован в JSON и обратно в экземпляр класса:

public class Container {

    private List<Base> derivedOne;
    private List<Base> derivedTwo;

    @JsonCreator
    public Container(@JsonProperty("derivedOne") List<Base> derivedOne, 
                     @JsonProperty("derivedTwo") List<Base> derivedTwo) {
        this.derivedOne = derivedOne;
        this.derivedTwo = derivedTwo;
    }

    public static class Derived1 extends Base {

        private String derivedField1;

        public Derived1(String derivedField1) {
            this.derivedField1 = derivedField1;
        }
    }

    public static class Derived2 extends Base {

        private String derivedField2;

        public Derived2(String derivedField2) {
            this.derivedField2 = derivedField2;
        }
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = 
                  JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Derived1.class, name = "one"),
        @JsonSubTypes.Type(value = Derived2.class, name = "two")
    })
    public abstract static class Base {
    }

}

, чтобы контейнер derivedOne содержал только экземпляры Derived1.class, а derivedTwo - только экземпляры Derived2.class.

Есть ли в Джексоне способ не использовать дополнительное свойство type для определения целевого класса по имени включаемого контейнера?

Я пытался заставить его работать с пользовательским TypeIdResolver, но безуспешно.

1 Ответ

0 голосов
/ 06 сентября 2018

Зависит от вашего значения JSON.

Вы можете использовать type , чтобы указать тип десериализации.

Ниже приведен полный код.

public class Container {

    private List<Base> derivedOne;
    private List<Base> derivedTwo;

    @JsonCreator
    public Container(@JsonProperty("derivedOne") List<Base> derivedOne,
                     @JsonProperty("derivedTwo") List<Base> derivedTwo) {
        this.derivedOne = derivedOne;
        this.derivedTwo = derivedTwo;
    }

    public static class Derived1 extends Base {

        private String derivedField1;

        public String getDerivedField1() {
            return derivedField1;
        }

        public void setDerivedField1(String derivedField1) {
            this.derivedField1 = derivedField1;
        }
    }

    public static class Derived2 extends Base {

        private String derivedField2;

        public String getDerivedField2() {
            return derivedField2;
        }

        public void setDerivedField2(String derivedField2) {
            this.derivedField2 = derivedField2;
        }
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
            JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Derived1.class, name = "one"),
            @JsonSubTypes.Type(value = Derived2.class, name = "two")
    })
    public abstract static class Base {
    }

    public static void main(String[] args) throws IOException {

        String jsonStr = "{\"derivedOne\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}],\"derivedTwo\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}]}";

        ObjectMapper objectMapper = new ObjectMapper();
        Container container = objectMapper.readValue(jsonStr, Container.class);
    }
}

использовать @JsonTypeIdResolver.

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
            JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonTypeIdResolver(ContainerResolver.class)
    public abstract static class Base {
    }

    public static void main(String[] args) throws IOException {

        String jsonStr = "{\"derivedOne\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}],\"derivedTwo\":[{\"type\":\"one\",\"derivedField1\":\"derivedField1\"},{\"type\":\"two\",\"derivedField2\":\"derivedField2\"}]}";

        ObjectMapper objectMapper = new ObjectMapper();
        Container container = objectMapper.readValue(jsonStr, Container.class);
    }


public class ContainerResolver extends TypeIdResolverBase {

    private JavaType superType;

    @Override
    public void init(JavaType baseType) {
        this.superType = baseType;
    }

    @Override
    public String idFromValue(Object value) {
        return idFromValueAndType(value, value.getClass());
    }

    @Override
    public String idFromValueAndType(Object value, Class<?> suggestedType) {

        String typeId = null;
        switch (suggestedType.getSimpleName()) {
            case "Derived1":
                typeId = "one";
                break;
            case "Derived2":
                typeId = "two";
        }
        return typeId;
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id)  throws IOException {

        Class<?> subType = null;
        switch (id) {
            case "one":
                subType = Container.Derived1.class;
                break;
            case "two":
                subType = Container.Derived2.class;
        }
        return context.constructSpecializedType(superType, subType);
    }

    @Override
    public JsonTypeInfo.Id getMechanism() {
        return JsonTypeInfo.Id.NAME;
    }
}

Эта статья может быть вам полезна.

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