繁体   English   中英

如果将属性键入Object,为什么使用Spring Data MongoDB读取嵌入式文档会失败?

[英]Why does reading embedded documents with Spring Data MongoDB fail if the property is typed to Object?

可以说我有以下Spring Data MongoDB接口:

public interface AccountRepository extends MongoRepository<Account, String> {}

现在,对象帐户显示在下面:

public class Account {

    @Id
    private String id;
    private Authentication authentication; //this is from the interface org.springframework.security.core.Authentication. Here I'm using org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken which implements the interface

当我调用下面的代码时,Jackson将不会保存帐户对象,因为我没有可用于映射内部Authentication对象的Authentication模型。 此外,Jackson要求有一个Authentication()的公共空构造函数,而Spring Authentication类没有这样的构造函数:

 @Autowired
 AccountRepository accountRepo;

accountRepo.save(Account);

我必须将帐户模型更改为以下内容,才能将身份验证另存为对象:

public class Account {

    @Id
    private String id;
    private Object authentication;

但是,当我尝试检索身份验证对象并将其重铸到身份验证对象时,出现此错误:

 {
  "timestamp": 1438441062525,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "org.springframework.data.mapping.model.MappingException",
  "message": "No property aPrincipal found on entity class com.futureprocessing.spring.infrastructure.AuthenticatedExternalWebService to bind constructor parameter to!",
  "path": "/account"
}

我总是可以将身份验证的各个部分分别保存在我的帐户对象(委托人,凭据和授予权限)中,但是如果需要的话,我将必须做一个构造函数来重新创建它。

没有简单的方法可以将身份验证对象另存为身份验证对象?

tl; dr

由于对象模型的更改以及先前版本使用更强的类型,数据库中已经存在的文档不包含任何类型信息。 可以理解的是,这导致Spring Data MongoDB无法推断出您想要读取嵌入式Authentication时,它可以推断出的只是Object类型的属性。

细节

这里的问题是,当authentication属性仍然是Authentication时,数据库存储了从类模型派生的文档时,数据库不包含任何类型信息。 如果在存储时该属性的值与声明的属性具有完全相同的类型,则Spring Data MongoDB不会写入任何类型信息来避免额外的开销。

如果您使用声明为authentication属性但包含Authentication对象的持久化Account ,Spring Data MongoDB将向嵌入的文档中添加_class属性以捕获类型信息,以便在读取文档时映射器知道要实例化的类型。

如果在文档中没有该附加属性,而在类型为Object的类中没有authentication属性,那么映射器将如何知道您在读取文档时要实例化Authentication对象?

解决方案

解决此问题的最简单方法是手动向数据库发布更新,并添加缺少的类型信息。 默认情况下,我们使用完全限定的类名,因此可以实现以下目的:

Update setTypeInformation = Update.update("authentication._class", Authentication.class.getName());
template.updateMulti(new Query(), setTypeInformation, Account.class);

Update语句将_class属性添加到嵌入式authentication文档中,并将其设置为Authentication的完全限定名称。 由于与所有现有文档匹配的空Query ,将对所有Accounts执行Update

更多参考

有关更多信息,请参见参考文档的相应部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM