草庐IT

java - Spring Data、Mongo 和 @TypeAlias : reading not working

coder 2023-11-01 原文

问题

不久前,我开始使用 MongoDB 和 Spring Data。我保留了大部分默认功能,因此我的所有文档都存储在 MongoDB 中,并带有一个指向实体的完全限定类名的 _class 字段。

我马上就“闻不到”了,但我没有管它。直到最近,当我重构一堆代码时,突然之间我的所有文档都无法从 MongoDB 中读回并转换为它们的(重构/重命名的)Java 实体。我很快意识到这是因为现在存在完全限定的类名不匹配。我也很快意识到——考虑到我可能会在未来的某个时候再次重构——如果我不想让我的所有数据变得不可用,我需要想出别的办法。

我尝试过的

这就是我正在做的,但我遇到了瓶颈。我认为我需要做以下事情:

  • @TypeAlias("ta") 注释每个实体,其中“ta”是唯一的、稳定的字符串。
  • 为 Spring Data 配置和使用不同的 TypeInformationMapper,以便在将我的文档转换回它们的 Java 实体时使用;例如,它需要知道“widget.foo”的类型别名指的是 com.myapp.document.FooWidget

我确定我应该使用 org.springframework.data.convert.MappingContextTypeInformationMapper 类型的 TypeInformationMapper。假设 MappingContextTypeInformationMapper 将扫描我的实体/文档以查找 @TypeAlias'ed 文档并存储别名->到->类映射。但我无法将其传递给我的 MappingMongoConverter;我必须传递 MongoTypeMapper 的子类型。因此,我正在配置一个 DefaultMongoTypeMapper,并传递一个 MappingContextTypeInformationMapper 的列表作为其“映射器”构造函数 arg。

代码

这是我的 spring XML 配置的相关部分:

<bean id="mongoTypeMapper" class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
    <constructor-arg name="typeKey" value="_class"></constructor-arg>
    <constructor-arg name="mappers">
        <list>
            <ref bean="mappingContextTypeMapper" />
        </list>
    </constructor-arg> 
</bean>

<bean id="mappingContextTypeMapper" class="org.springframework.data.convert.MappingContextTypeInformationMapper">
    <constructor-arg ref="mappingContext" />
</bean>

<bean id="mappingMongoConverter"
    class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
    <constructor-arg ref="mongoDbFactory" />
    <constructor-arg ref="mappingContext" />
    <property name="mapKeyDotReplacement" value="__dot__" />
    <property name="typeMapper" ref="mongoTypeMapper"/>
 </bean>

 <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg ref="mongoDbFactory" />
    <constructor-arg ref="mappingMongoConverter" />
 </bean>

这是一个示例实体/文档:

@Document(collection="widget")
@TypeAlias("widget.foo")
public class FooWidget extends Widget {

    // ...

}

一个重要的注意事项是,任何此类“Widget”实体都作为嵌套文档存储在 Mongo 中。所以实际上您不会在我的 MongoDB 实例中找到填充的“Widget”集合。相反,更高级别的“页面”类可以包含多个“小部件”,如下所示:

@Document(collection="page")
@TypeAlias("page")
public class Page extends BaseDocument {

    // ...

    private List<Widget> widgets = new ArrayList<Widget>();

}

我遇到的错误

我可以在 Mongo 中保存一个页面以及许多嵌套的小部件。但是当我尝试重新阅读所述页面时,我得到如下内容:

org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.myapp.document.Widget]: Is it an abstract class?

我确实可以在 Mongo 中看到包含 "_class": "page" 的页面,嵌套的小部件也包含 "_class": "widget.foo" 它只是出现就像映射没有被反向应用一样。

有什么我可能遗漏的吗?

最佳答案

在默认设置中,MappingMongoConverter 创建一个 DefaultMongoTypeMapper,后者又创建一个 MappingContextTypeInformationMapper

最后一个类负责维护 TypeInformation 和别名之间的 typeMap 缓存。

该缓存填充在两个地方:

  1. 在构造函数中,对于每个 mappingContext.getPersistentEntities()
  2. 编写别名类型的对象时。

因此,如果您想确保别名在任何上下文中都能被识别,您需要确保所有使用别名的实体都是 mappingContext.getPersistentEntities() 的一部分。

你如何做到这一点取决于你的配置。例如:

  • 如果您正在使用 AbstractMongoConfiguration,您可以覆盖它的 getMappingBasePackage() 以返回包含所有实体的包的名称。
  • 如果您使用的是 spring boot,则可以使用 @EntityScan 声明要扫描哪些包以查找实体
  • 在任何情况下,您始终可以使用 mongoMappingContext.setInitialEntitySet()
  • 使用自定义集(来自静态列表或自定义扫描)配置它

请注意,对于要通过扫描发现的实体,必须使用 @Document@Persitent 对其进行注释。

更多信息可以在 spring-data-commons Developer Guide 中找到

关于java - Spring Data、Mongo 和 @TypeAlias : reading not working,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26823359/

有关java - Spring Data、Mongo 和 @TypeAlias : reading not working的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  8. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  9. java - Ruby 相当于 Java 的 Collections.unmodifiableList 和 Collections.unmodifiableMap - 2

    Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur

  10. java - Java 的 StringReader 的 Ruby 等价物是什么? - 2

    在Java中,可以像这样从一个字符串创建一个IO流:Readerr=newStringReader("mytext");我希望能够在Ruby中做同样的事情,这样我就可以获取一个字符串并将其视为一个IO流。 最佳答案 r=StringIO.new("mytext")和here'sthedocumentation. 关于java-Java的StringReader的Ruby等价物是什么?,我们在StackOverflow上找到一个类似的问题: https://st

随机推荐