【问题标题】:PersistenceConstructor argument variable name doesn't match instance variable namePersistenceConstructor 参数变量名称与实例变量名称不匹配
【发布时间】:2012-12-12 03:11:18
【问题描述】:

我正在尝试使用spring-data-mongodb 版本1.1.1.RELEASE 保留以下对象:

@Document
public static class TestObject {

    private final int m_property;

    @PersistenceConstructor
    public TestObject(int a_property) {
        m_property = a_property;
    }

    public int property() {
        return m_property;
    }

}

当我尝试从数据库中读回对象时,我得到一个MappingException(请参阅下面的完整堆栈跟踪)

我的小组使用的命名约定要求参数变量名称以a_ 开头,实例变量名称以m_ 开头。似乎spring-data-mongodb 假设构造函数参数变量名称必须与对象实例变量名称匹配。

  • 为什么spring-data-mongodb 不使用我在构造函数中定义的实例变量映射的构造函数参数?
  • 是否有另一种方法来定义此映射,以便 spring-data-mongodb 正确构造我的对象,或者是我唯一的选择来打破命名约定?

.

Exception in thread "main" org.springframework.data.mapping.model.MappingException: No property a_property found on entity class com.recorder.TestRecorder$TestObject to bind constructor parameter to!
    at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:90)
    at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:70)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:229)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:209)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:173)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:169)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:72)
    at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:1820)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1542)
    at org.springframework.data.mongodb.core.MongoTemplate.findAll(MongoTemplate.java:1064)
    at com.recorder.TestRecorder.main(TestRecorder.java:43)

【问题讨论】:

  • 这真是蹩脚的命名约定,没有任何意义。

标签: java naming-conventions spring-data mongodb-java spring-data-mongodb


【解决方案1】:

tl;dr

我们需要依赖构造函数参数名称来匹配字段名称,以找出要拉入文档的哪个字段。如果您想自定义这个,请在​​构造函数参数上使用@Value("#root.field_name")

长篇大论

如果您使用带参数的构造函数让 Spring Data 使用此构造函数实例化给定的类,我们必须在调用时将参数传递给构造函数。为了找出我们必须提交的文档字段,我们需要检查匹配属性以进行潜在的字段名称自定义。请参阅以下示例:

@Document
class MyEntity {

  @Field("foo")
  private String myField;

  public MyEntity(String myField) {
    this.myField = myField;
  }
}

在这种情况下,我们需要将字段foo 通过管道传递到构造函数中,如果我们无法以某种方式获取对该属性的引用,则无法找到相关信息。如果构造函数参数名称不同,我们应该如何可靠地找出哪个字段值实际上应该用作参数?您在问题中显示的示例可能永远开箱即用,因为您的文档将包含一个 m_property 字段,并且绝对无法确定您实际上想要注入它,除了添加更明确的配置。

要自定义此行为,您可以使用 Spring 的 @Value 注释并将自定义文档字段注入构造函数。文档本身可通过#root 变量获得。因此,您可以轻松地将我上面的示例更改为:

@Document
class MyEntity {

  @Field("foo")
  private String myField;

  public MyEntity(@Value("#root.foo") String somethingDifferent) {
    this.myField = somethingDifferent;
  }
}

我强烈建议您将自定义字段名称添加到您的属性中,并且您不想将属性命名约定暴露给数据库。 pf @Value 的用法在 reference docs 中有简要提及,但我创建了 a ticket 以改进文档并使其更加明显。

【讨论】:

  • 给您一个后续问题 - 如果我按照您的建议进行操作,它似乎适用于仅包含原语的对象,但每当我尝试使用包含其他对象的对象时都会出现异常。你知道这里发生了什么吗?我已经在Question 13854753 中列出了详细信息
  • 仅供参考 - 我创建了 DATAMONGO-592 来跟踪无法使用包含其他对象的对象的问题。谢谢你的帮助!!
  • 哦,我多么喜欢 stackoverflow 和那些为它做出贡献的人!我本可以花几天时间试图找出问题所在,你只是节省了我所有的时间和挫败感。谢谢!
  • 如果这种行为记录在@PersistenceConstructor上会很好
【解决方案2】:

您可以使用一些自定义转换器(并删除@PersistenceConstructor):

// DB => Java
package com.recorder.converters;

public class TestObjectReadConverter implements Converter<DBObject, TestObject> 
{
   public TestObject convert(final DBObject source) {
       return new TestObject((Integer) source.get("m_property"));
   }
}

.

// JAVA => DB
package com.recorder.converters;

public class TestObjectWriteConverter implements Converter<TestObject, DBObject> 
{
    public DBObject convert(final TestObject source) {
        return new BasicDBObjectBuilder("m_property", source.property()).get();
    }
}

别忘了声明那些(xml配置):

<mongo:mapping-converter base-package="com.recorder">
    <mongo:custom-converters>
        <mongo:converter>
             <bean class="com.recorder.converters.TestObjectReadConverter" />
        </mongo:converter>
        <mongo:converter>
             <bean class="com.recorder.converters.TestObjectWriteConverter"/>
        </mongo:converter>
    </mongo:custom-converters>
</mongo:mapping-converter>

this reference

旁注:这是一种变通方法,我认为命名约定并不意味着您需要变通变通。也许是时候让您的团队“重新考虑”这些命名约定了(在这种情况下是为了提高效率)。

【讨论】:

    猜你喜欢
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 2014-06-15
    • 2023-03-03
    • 1970-01-01
    相关资源
    最近更新 更多