Java - как десериализовать в логически идентичный класс? - PullRequest
1 голос
/ 21 октября 2019

Я не хочу вдаваться в подробности, поэтому я постараюсь сделать это как можно проще. У нас есть приложение (Java, Spring Boot), которое генерирует некоторую информацию, которую мы затем сериализуем и храним в базе данных. Чтобы его сериализовать, мы используем ObjectMapper:

final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.enableDefaultTyping(); // default to using DefaultTyping.OBJECT_AND_NON_CONCRETE
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

manifestJson = mapper.writeValueAsString(manifest);

, а затем JSON сохраняется в базе данных. Yyppy Yay. manifest - сложный объект, который содержит ряд других объектов и информацию, которая используется для создания конечного продукта. Проблема в том, что мы пытаемся использовать эту информацию для создания нового объекта. FQN исходного класса хранится вместе с информацией (имеет смысл). Но чтение информации происходит в другом месте / приложении. Поэтому, хотя исходное пространство имен, которое хранилось с помощью json, имело тип abcdefclass1, сейчас мы пытаемся считать его обратно в класс abcghifclass1 ... логически class1 одинаков в обоих пространствах имен, фактически он был скопирован непосредственно из одного в другое. ,Разница лишь в именах пакетов.

Естественно, когда мы затем пытаемся десериализовать JSON, он выдает ошибку о том, что не найден тип, исходный тип находится в исходном проекте / приложении, а «новый» тип находится в текущем проекте. Мы могли бы сослаться на исходное приложение из вторичного приложения, но по функциональным причинам мы пытаемся поддерживать разделение между ними.

Итак, вопрос в том, как получить сериализованный объект из одного проекта, а затемдесериализовать его в другой класс, который логически идентичен?

1 Ответ

0 голосов
/ 22 октября 2019

По умолчанию, когда набор текста не используется, вы можете сгенерировать полезную нагрузку JSON, которую впоследствии можно будет десериализовать для любой модели, которая соответствует этому JSON. Или даже к Map или / и List объектам, если вы вообще не хотите создавать модель.

В вашем случае, когда JSON полезные нагрузки используются двумя разными приложениями с двумя разными моделямиВы не должны прикреплять информацию о классе, потому что она не предоставляет никакой дополнительной информации для другой модели. Один JSON можно десериализовать разными способами и использовать для разных целей, поэтому его связывание с одной моделью вызывает проблемы, как вы заметили в своем примере. Таким образом, если это возможно, отключите набор текста и предоставьте явно всю информацию, необходимую позже для воссоздания того же объекта из JSON.

Если это невозможно, просто предоставьте свой пользовательский TypeIdResolver и сопоставьте один классот одной модели до аналогичного класса в другой модели. Простой пример, который показывает идею:

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.SimpleType;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        SimpleModule model2Module = new SimpleModule("Model2");
        model2Module.setMixInAnnotation(PojoA2.class, CustomJsonTypeIdResolverMixIn.class);
        model2Module.setMixInAnnotation(PojoB2.class, CustomJsonTypeIdResolverMixIn.class);
        model2Module.setMixInAnnotation(PojoC2.class, CustomJsonTypeIdResolverMixIn.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        mapper.registerModule(model2Module);

        String json = mapper.writeValueAsString(new PojoA());

        System.out.println(json);

        System.out.println(mapper.readValue(json, PojoA.class));
        System.out.println(mapper.readValue(json, PojoA2.class));
    }
}

@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM)
@JsonTypeIdResolver(value = Model2ClassNameIdResolver.class)
interface CustomJsonTypeIdResolverMixIn { }

class Model2ClassNameIdResolver extends ClassNameIdResolver {

    private final Map<String, JavaType> types = new HashMap<>();

    public Model2ClassNameIdResolver() {
        super(null, null);
        types.put("com.celoxity.PojoA", SimpleType.constructUnsafe(PojoA2.class));
        types.put("com.celoxity.PojoB", SimpleType.constructUnsafe(PojoB2.class));
        types.put("com.celoxity.PojoC", SimpleType.constructUnsafe(PojoC2.class));
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id) throws IOException {
        JavaType javaType = types.get(id);
        if (javaType != null) {
            return javaType;
        }

        return super.typeFromId(context, id);
    }
}

class PojoA2 {

    private PojoB2 b;
}

class PojoB2 {

    private List<PojoC2> c;
}

class PojoC2 {

    private String s;
    private int i;
}

class PojoA {

    private PojoB b;
}

class PojoB {

    private List<PojoC> c;
}

class PojoC {

    private String s;
    private int i;
}

Две модели: PojoA, PojoB, PojoC и PojoA2, PojoB2, PojoC2 имеют одинаковую структуру и имеют только разныеимена. PojoA совпадает с PojoA2 и т. Д.

Над отпечатками кода:

["com.celoxity.PojoA",{"b":["com.celoxity.PojoB",{"c":["java.util.ArrayList",[["com.celoxity.PojoC",{"s":"Vika","i":22}]]]}]}]

и позже:

PojoA{b=PojoB{c=[PojoC{s='Vika', i=22}]}}
PojoA2{b=PojoB2{c=[PojoC2{s='Vika', i=22}]}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...