Spring数据Mongo - 如何映射继承的POJO实体?

Spring Data Mongo - How to map inherited POJO entities?

我是 Spring 的新手,但我想尝试一下这个项目。 我有一个 MongoDB 数据库,其中填充了相当复杂的文档。我想使用 Spring 数据 Mongo 来查询(没有其他 CRUD 操作)数据库。

我已经使用 POJO 描述了我的文档实体,但其中一些是抽象的(参见 GeometryGeoJSON 用于接受所有类型的 GeoJson 几何,或 Contact 可以是 PersonOrganisation。下面提供 GitHub 存储库的 link。

对该实体定义进行测试,抛出 java.lang.InstantiationError 是公平的,因为在那些抽象 类.

中没有定义构造函数

这里是GitHub repository,以备不时之需。

我对这一切感到有点迷茫,但我会更仔细地查看文档。

你会如何面对这个问题?

我会回答我自己的问题。如评论中所述,解决方案是使用 Converter.

这是我打算用我的 class 模型实现的示例:

A Contact 可以是 PersonOrganisation

如果您正在使用 spring-data-mongodb MongoRepository to write data in your database according to your entity model, a _class field will be added to document roots and to complex property types (see this section)。此字段存储 Java class 的完全限定名称,它允许在从 MongoDb 文档映射到 Spring 数据模型时消除歧义。

如果您的应用程序只是从数据库中读取文档(没有 _class 字段),您需要告诉 Spring 数据在映射 Contact 时要实例化哪个 class . Spring-data 允许您使用 Converter 自定义默认类型映射行为。使用显式 Converter override default mapping for the class。您需要明确映射整个 class。这是我的 ContactReadConverter:

的示例
@ReadingConverter
public class ContactReadConverter implements Converter<Document, Contact> {

    @Override
    public Contact convert(Document source) {
        if (source.get("firstName") == null) {
            Organisation organisation = new Organisation();
            I18n name = new I18n();
            name.setEn(source.get("name", Document.class).get("en", String.class));
            name.setFr(source.get("name", Document.class).get("fr", String.class));
            organisation.setName(name);
            organisation.setAcronym(source.get("acronym", String.class));
            organisation.setRole(source.get("role", String.class));
            return organisation;
        }
        Person person = new Person();
        person.setFirstName(source.get("firstName", String.class));
        person.setLastName(source.get("lastName", String.class));
        person.setRole(source.get("role", String.class));
        person.setEmail(source.get("email", String.class));
        person.setOrcId(source.get("orcId", String.class));
        if (source.get("organisation") != null) {
            Document sourceOrg = source.get("organisation", Document.class);
            Organisation organisation = new Organisation();
            organisation.setAcronym(sourceOrg.get("acronym", String.class));
            organisation.setRole(sourceOrg.get("role", String.class));
            if (sourceOrg.get("name") != null) {
                I18n name = new I18n();
                name.setFr(sourceOrg.get("name", Document.class).get("fr", String.class));
                name.setEn(sourceOrg.get("name", Document.class).get("en", String.class));
                organisation.setName(name);
            }
            person.setOrganisation(organisation);
        }
        return person;
    }
}

然后,需要注册新定义的转换器:

@Configuration
public class DataportalApplicationConfig extends AbstractMongoConfiguration {
    @Value("${spring.data.mongodb.uri}")
    private String uri;
    @Value("${spring.data.mongodb.database}")
    private String database;
    @Override
    public MongoClient mongoClient() {
        return new MongoClient(new MongoClientURI(uri));
    }
    @Override
    protected String getDatabaseName() {
        return database;
    }    
    @Bean
    @Override
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converterList = new ArrayList<>();
        converterList.add(new ContactReadConverter());
        return new MongoCustomConversions(converterList);
    }
}

希望对您有所帮助。