Как заставить @TypeAlias ​​работать при чтении документа после обновления до Spring Boot 2.1.3, когда он работал в 1.4.5 - PullRequest
1 голос
/ 12 марта 2019

В настоящее время я использую данные весны mongodb, а файл конфигурации расширяется. AbstractMongoConfiguration:

@Configuration
@EnableMongoRepositories(basePackages = "com.mycompany")
@EnableMongoAuditing
public class MongoConfig extends AbstractMongoConfiguration
{

Я переопределяю метод getMappingBasePackage(), чтобы настроить пакет на сканирование следующим образом:

    @Override
    protected String getMappingBasePackage() 
    {
        return "com.mycompany";
    }

Я отлаживал код и заметил несколько интересных вещей:

  1. Есть два места, где я получаю java.lang.InstantiationError.Оба случая происходят, когда я пытаюсь прочитать документ из монго, в котором есть ссылка на абстрактный класс (ParentClass).Он пытается создать экземпляр абстрактного класса вместо того, чтобы найти аннотацию @TypeAlias, которую я добавил к дочерним классам.

Вот как выглядит мой ParentClass:

@Document
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXISTING_PROPERTY, visible=true, property="type")
@JsonSubTypes({
    @Type(value=Child1.class, name="JSON_TYPE_CHILD1"),
    @Type(value=Child2.class, name="JSON_TYPE_CHILD2"),
    @Type(value=Child3.class, name="JSON_TYPE_CHILD3")
})
public abstract class ParentClass
{
...

Мои дочерние классы выглядят так:

@Document
@JsonTypeName("JSON_TYPE_CHILD1")
@TypeAlias("ALIAS_TYPE_CHILD1")
public class Child1 extends ParentClass
{
...

Вот как выглядит (упрощенно) json, в котором я пытаюсь прочитать:

{
    "_id" : ObjectId("5c86d31388f13344f4098c64"),
    "listOfWrapperClass" : [ 
        {
            "parentClass" : {
                "type" : "JSON_TYPE_CHILD1",
                "prop1" : 50.0,
                "prop2" : 50.0,
                "_class" : "ALIAS_TYPE_CHILD1"
            },
            "isReportOutOfDate" : false,

        }
    ],
    "_class" : "com.mycompany.domain.job.Job"
}

Когда я отлаживаю данные пружиныпроблема возникает в DefaultTypeMapper:

    private TypeInformation<?> getFromCacheOrCreate(Alias alias) {

        Optional<TypeInformation<?>> typeInformation = typeCache.get(alias);

        if (typeInformation == null) {
            typeInformation = typeCache.computeIfAbsent(alias, getAlias);
        }

        return typeInformation.orElse(null);
    }

Он отлично загружает класс-оболочку, но когда он попадает в дочерний класс, псевдоним устанавливается в «ALIAS_TYPE_CHILD1», как и должно быть, но в typeCache следующие значения:

    {
        NONE=Optional.empty, 
        ALIAS_TYPE_CHILD1=Optional.empty, 
        com.mycompany.domain.job.Job=Optional[com.mycompany.domain.job.Job]
    }

Поскольку ключ "ALIAS_TYPE_CHILD1" имеет в качестве значения Optional.empty, код не получает правильный целевой тип для загрузки и поэтому использует rawType, который является ParentClass.Который взрывается, потому что не может создать экземпляр абстрактного класса.Вот трассировка стека:

Caused by: java.lang.InstantiationError: com.mycompany.domain.job.base.ParentClass
    at com.mycompany.domain.job.base.ParentClass_Instantiator_q3kytg.newInstance(Unknown Source)
    at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:226)
    at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:84)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:272)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:245)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1491)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1389)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readProperties(MappingMongoConverter.java:378)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.populateProperties(MappingMongoConverter.java:295)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:275)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:245)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readCollectionOrArray(MappingMongoConverter.java:1038)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1489)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1389)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readProperties(MappingMongoConverter.java:378)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.populateProperties(MappingMongoConverter.java:295)
    at ...

Странная вещь, если я вставляю новый документ с @TypeAlias("ALIAS_TYPE_CHILD1") first , упомянутый выше typeCache заполняется правильно так:

{  
   NONE=Optional.empty,
   ALIAS_TYPE_CHILD1=Optional[com.mycompany.domain.job.base.Child1],
   com.mycompany.domain.job.Job=Optional[com.mycompany.domain.job.Job]
} 

Когда я обнаруживаю OneOne сразу после вставки, я могу читать в документе без ошибок, поскольку он использует Child1 для создания экземпляра pojo вместо ParentClass.Если я пытаюсь читать сначала, тогда не имеет значения, вставлю ли я после этого или нет, потому что typeCace вводит туда неверное значение и использует его до тех пор, пока вы не перезапустите сервер.

Я думаю, что естьбыло изменение в конфигурации или в настройках по умолчанию.Мне удалось решить все другие проблемы с обновлением, но этот сбил меня с толку.Я был бы шокирован, если в весенних данных есть реальная проблема, потому что я уверен, что кто-то уже столкнулся с этой проблемой, потому что я не могу быть единственным, кто пытается использовать @TypeAlias с spring-data-mongodb.Не говоря уже о том, что все прекрасно работает с предыдущей версией загрузочной пружины, которую я использовал (1.4.5, которая использует spring-data-mongodb 1.9.8.RELEASE).

Любые мысли или советы о том, что попробовать дальше, приветствуются.Я просто не знаю, что делать дальше.

1 Ответ

2 голосов
/ 12 марта 2019

Проблема заключалась в том, что typeCache не заполнялся в первую очередь при запуске сервера. Это потому, что protected String getMappingBasePackage() устарела. Вы должны использовать protected Collection<String> getMappingBasePackages() вместо этого, и тогда все прекрасно работает.

Переопределение этого метода решает проблему:

    @Override
    protected Collection<String> getMappingBasePackages()
    {
        return Arrays.asList("com.mycompany");
    }
...