Java PersistenceConstructor参数变量名不为';实例变量名不匹配

Java PersistenceConstructor参数变量名不为';实例变量名不匹配,java,naming-conventions,spring-data,mongodb-java,spring-data-mongodb,Java,Naming Conventions,Spring Data,Mongodb Java,Spring Data Mongodb,我正在尝试使用spring数据mongodbversion1.1.1.RELEASE持久化以下对象: @Document public static class TestObject { private final int m_property; @PersistenceConstructor public TestObject(int a_property) { m_property = a_property; } public i

我正在尝试使用
spring数据mongodb
version
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
(参见下面的完整stacktrace)

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

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


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

//DB=>Java
包com.recorder.converters;
公共类TestObjectReadConverter实现转换器
{
公共TestObject转换(最终DBObject源){
返回新的TestObject((Integer)source.get(“m_属性”);
}
}

//JAVA=>DB
包com.recorder.converters;
公共类TestObjectWriteConverter实现转换器
{
公共DBObject转换(最终测试对象源){
返回新的BasicDBObjectBuilder(“m_属性”,source.property()).get();
}
}
不要忘记声明这些(xml配置):


旁注:这是一个解决办法,我不认为命名约定应该如此严格以至于需要解决。也许是时候让您的团队“重新考虑”这些命名约定了(在这种情况下,为了提高效率)。

tl;dr

我们需要依赖构造函数参数名来匹配字段名,以确定要拉入文档的哪个字段。如果要自定义此值,请在构造函数参数上使用
@Value(“#root.field_name”)

说来话长

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

@Document
class MyEntity {

  @Field("foo")
  private String myField;

  public MyEntity(String myField) {
    this.myField = myField;
  }
}
在这种情况下,我们需要通过管道将字段
foo
导入构造函数,如果我们不能以某种方式获得对该属性的引用,那么就无法找到这一点。如果构造函数参数名是不同的,我们应该如何可靠地找出哪个字段值应该实际用作参数?您在问题中展示的示例永远无法开箱即用,因为您的文档将包含一个
m_属性
字段,除了添加更明确的配置之外,根本无法确定您是否确实希望将其注入

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

@Document
class MyEntity {

  @Field("foo")
  private String myField;

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

我强烈建议您将自定义字段名添加到属性中,同时不要向数据库公开属性命名约定。在中简要提到了pf
@Value
的用法,但我创建它是为了改进文档并使其更加明显。

还有一个问题需要回答-如果我按照您的建议去做,它似乎适用于只包含原语的对象,但每当我尝试使用包含其他对象的对象时,我都会遇到一个异常。你知道这是怎么回事吗?我已经在FYI中列出了详细信息-我创建这些信息是为了跟踪无法使用包含其他对象的对象的问题。谢谢你的帮助!!哦,我多么爱stackoverflow和那些在其中做出贡献的人!我本可以花上几天的时间来找出问题所在,你帮我省去了所有的时间和挫折。非常感谢。如果在@persistenceconstructor上记录这种行为就好了。这是一种毫无意义的糟糕的命名约定。
// 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();
    }
}
<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>
@Document
class MyEntity {

  @Field("foo")
  private String myField;

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

  @Field("foo")
  private String myField;

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