简体   繁体   English

构造函数参数和Spring数据反序列化问题

[英]constructor Arguments and Spring Data De-Serialization Issue

Using Spring Data with MongoDB. 在MongoDB中使用Spring Data。

Problem is in instantiating a bean retrieved from Mongo because the constructor has some argument which actually is inside a nested object. 问题在于实例化从Mongo检索到的bean,因为构造函数具有一些实际上位于嵌套对象内部的参数。 Persistance is not an issue. 持久性不是问题。 Retrieval Is. 检索是。

Class structure is as below where B is nested inside A. A sets B instantiating it using one of its constructor Params. 类结构如下,其中B嵌套在A内。A使用其构造函数Params之一实例化B的集合B。

Class A A级

Class A{
 int prop1;
 B b; 

 @JsonCreator
 public A(  @JsonProperty int prop1, @JsonProperty  int prop2){
  this.prop1 = prop1;
  this.b = new B(prop2);
 }
}

Class B which is nested inside A 嵌套在A内的B类

Class B(){
 int prop2;

 @JsonCreator
 public B(@JsonProperty int prop2){
  this.prop2 = prop2;
 }
}

When Object is received by REST API in the below Json form: REST API以以下Json形式接收Object时:

 {"prop1":"Hello1","prop2":"Hello2"}

Spring Controller receives it and maps it correctly to Object A. Since Spring uses no-arg constructor by default, I used jsoncreator annotation on arg-constructor and it is added to MongoDB without any fuss. Spring Controller接收它并将其正确映射到对象A。由于Spring默认使用no-arg构造函数,因此我在arg-constructor上使用了jsoncreator批注,并且将其添加到MongoDB中没有大惊小怪。

The data is stored in below format as per bean structure which is right. 数据按照正确的bean结构以以下格式存储。

      {"prop1":"Hello1","b":{"prop2":"Hello2"}}

Coming to the problem: Error comes when I try to retrieve from Mongo. 出现问题:当我尝试从Mongo检索时出现错误。 It says: 它说:

 org.springframework.data.mapping.model.MappingException: No property prop2 
 found on entity class A to bind constructor parameter to

How Can I tell SpringData to use object B which contains prop2 when getting it from SpringData? 从SpringData获取对象时,如何告诉SpringData使用包含prop2的对象B? (Perhaps thats not possible) (也许那不可能)

I thought perhaps adding one more constructor will do the trick, where I use object B as one of the constructor arguments like below: 我以为也许再增加一个构造函数就能解决问题,在这里我将对象B用作构造函数参数之一,如下所示:

   public A(int prop1, B b){
       ......
       ......
   }

Adding one more constructor works with ObjectMapper but again not with SpringData. 再添加一个构造函数可以使用ObjectMapper,但是不能再使用SpringData。

This time a new exception is thrown : 这次抛出了一个新的异常:

      org.springframework.data.mapping.model.MappingInstantiationException: 
      Failed to instantiate A using constructor NO_CONSTRUCTOR with 
      arguments. 

I checked the above error where List is being used/not used , but I tried both ways and didnt resolve. 我在使用/未使用List的地方检查了以上错误,但是我尝试了两种方法但都没有解决。

Please note: I am using object B as nested since it contains common properties which will be used by lot of other beans ( could be abstract class , but I will need to try that later, but somehow abstract class seems limiting) 请注意:我将对象B嵌套使用,因为它包含将由许多其他bean使用的公共属性(可能是抽象类,但是我稍后需要尝试,但是抽象类似乎有限制)

How do have SpringData create object A ? SpringData如何创建对象A?

Looks like a faux pas. 看起来像个假人。

Should have used better terms in searching. 应该在搜索中使用更好的术语。 Would have found the correct answer. 会找到正确的答案。 Just in case somebody faces this problem ... 万一有人面对这个问题...

Some searching led me to this below question: 一些搜索使我想到了以下问题:

How exactly does spring-data-mongodb handle constructors when rehydrating objects? 在为对象补水时,spring-data-mongodb如何正确处理构造函数?

The above question mentions few things which gave me the solution. 上面的问题提到了一些给我解决方案的事情。 The answer lies in using another constructor for deserialization from SpringData to bean. 答案在于使用另一个构造函数从SpringData到bean反序列化。 This constructor needs to be annotated with: 该构造函数需要添加以下注释:

    @PersistenceConstructor

In the example in the question, if I use the second constructor with this annotation, retrieval works. 在问题的示例中,如果我将第二个构造函数与该注释一起使用,则检索有效。

        @PersistenceConstructor
        public A(int prop1, B b){
         ......
         ......
        }

So now , I have 2 constructors , one with @jsoncreator and another with @PersistenceConstructor. 所以现在,我有2个构造函数,一个带有@jsoncreator,另一个带有@PersistenceConstructor。 But to add , this other constructor can be private also if you have no other use for it other than for retrieval from SpringData and it will not be used in code by anybody thus leaving your Business Logic intact. 但是要补充一点,如果您除了从SpringData检索之外没有其他用途,则该其他构造函数也可以是私有的,并且任何人都不会在代码中使用它,因此您的业务逻辑保持不变。 Hence the below will also work: 因此,以下内容也将起作用:

        @PersistenceConstructor
        private A(int prop1, B b){
         ......
         ......
        }

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

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