【问题标题】:JsonMappingException: No suitable constructor found for type [simple type, class ]: can not instantiate from JSON objectJsonMappingException:没有为类型 [简单类型,类] 找到合适的构造函数:无法从 JSON 对象实例化
【发布时间】:2011-11-29 08:38:21
【问题描述】:

我在尝试获取 JSON 请求并对其进行处理时收到以下错误:

org.codehaus.jackson.map.JsonMappingException: 没有找到适合类型 [simple type, class com.myweb.ApplesDO] 的构造函数:无法从 JSON 对象实例化(需要添加/启用类型信息?)

这是我要发送的 JSON:

{
  "applesDO" : [
    {
      "apple" : "Green Apple"
    },
    {
      "apple" : "Red Apple"
    }
  ]
}

在Controller中,我有以下方法签名:

@RequestMapping("showApples.do")
public String getApples(@RequestBody final AllApplesDO applesRequest){
    // Method Code
}

AllApplesDO 是 ApplesDO 的包装器:

public class AllApplesDO {

    private List<ApplesDO> applesDO;

    public List<ApplesDO> getApplesDO() {
        return applesDO;
    }

    public void setApplesDO(List<ApplesDO> applesDO) {
        this.applesDO = applesDO;
    }
}

ApplesDO:

public class ApplesDO {

    private String apple;

    public String getApple() {
        return apple;
    }

    public void setApple(String appl) {
        this.apple = apple;
    }

    public ApplesDO(CustomType custom){
        //constructor Code
    }
}

我认为 Jackson 无法将 JSON 转换为子类的 Java 对象。请帮助杰克逊将 JSON 转换为 Java 对象的配置参数。我正在使用 Spring 框架。

编辑:在上述示例类中包含导致此问题的主要错误 - 请查看已接受的解决方案答案。

【问题讨论】:

  • 我在上面的代码中没有看到任何子类,这段代码是你尝试的还是你在编一个更简单的例子?
  • 我添加了一个答案,并对其工作原理进行了更多解释。基本上,您需要意识到 Java 不会在运行时保留方法参数名称。

标签: java json spring annotations jackson


【解决方案1】:

所以,我终于意识到问题所在了。这不是我怀疑的杰克逊配置问题。

其实问题出在ApplesDO类:

public class ApplesDO {

    private String apple;

    public String getApple() {
        return apple;
    }

    public void setApple(String apple) {
        this.apple = apple;
    }

    public ApplesDO(CustomType custom) {
        //constructor Code
    }
}

为该类定义了一个自定义构造函数,使其成为默认构造函数。引入虚拟构造函数使错误消失:

public class ApplesDO {

    private String apple;

    public String getApple() {
        return apple;
    }

    public void setApple(String apple) {
        this.apple = apple;
    }

    public ApplesDO(CustomType custom) {
        //constructor Code
    }

    //Introducing the dummy constructor
    public ApplesDO() {
    }

}

【讨论】:

  • 请问CustomType 是从哪里来的。我正在尝试这样的结构,但我对 Java 完全陌生。
  • 您可以将杰克逊与内部(嵌套)类一起使用,在这种情况下序列化工作得很好。唯一的绊脚石是内部类必须标记为“静态”才能使反序列化正常工作。请参阅此处的说明:cowtowncoder.com/blog/archives/2010/08/entry_411.html
  • 有人能解释一下为什么会这样吗?我有一个非常相似的错误。认为所有正确的构造函数都已到位,但无法反序列化。它只有在我添加了一个虚拟构造函数之后才起作用,在阅读了这篇文章之后。
  • @Suman 我不会将其称为虚拟构造函数——它只是默认构造函数。它不仅完全有效,而且是多种 java bean 类型处理所必需的。 (而且,当然,它绊倒了我。:-))
  • 如果您不想添加默认构造函数(例如,当您处理不可变对象时)。您将不得不告诉使用 JsonCreator 注释使用哪个构造函数或工厂方法来实例化对象。
【解决方案2】:

发生这种情况的原因如下:

  1. 你的内部类应该被定义为static

    private static class Condition {  //jackson specific    
    }
    
  2. 可能是你的类中没有默认构造函数(更新:这似乎不是这种情况)

    private static class Condition {
        private Long id;
    
        public Condition() {
        }
    
        // Setters and Getters
    }
    
  3. 可能是您的 Setter 定义不正确或不可见(例如私有 setter)

【讨论】:

  • 静态类在我的情况下有所不同。谢谢!
  • 当然,您不需要需要声明一个空的、无参数的默认构造函数Java does it for you! (只要您不定义任何其他构造函数。)
  • @Jonik,对!我的答案很旧,如果我没记错的话,因为杰克逊使用反射来进入内部类,我想它需要定义默认构造函数(在较新版本中也可能不是这种情况),但因为我不是确定你是对的。
  • 是的,我的经验是使用 Jackson 2.4.4:确实 Java 的隐式默认构造函数就足够了。 only 如果您定义了接受参数的 other 构造函数,则需要显式编写无参数构造函数(即,当 Java 不为您生成无参数构造函数时) )。
  • 和我一样,静态类拯救了一天。
【解决方案3】:

我想为此添加另一个不需要虚拟构造函数的解决方案。由于虚拟构造函数有点混乱并且随后令人困惑。我们可以提供一个安全的构造函数,并通过注释构造函数参数,我们允许杰克逊确定构造函数参数和字段之间的映射。

因此以下内容也将起作用。注意注解内的字符串必须与字段名匹配。

import com.fasterxml.jackson.annotation.JsonProperty;
public class ApplesDO {

        private String apple;

        public String getApple() {
            return apple;
        }

        public void setApple(String apple) {
            this.apple = apple;
        }

        public ApplesDO(CustomType custom){
            //constructor Code
        }

        public ApplesDO(@JsonProperty("apple")String apple) {
        }

}

【讨论】:

  • 这个解决方案成功了。我只想提一下,我有一个构造函数,但是参数的名称与instance-parameters的名称不同,因此无法映射。添加注释解决了它,但重命名参数可能也可以。
  • 响应中没有构造函数参数怎么办?可以通过其他方式注入吗?
  • 这里发送的唯一重要数据是响应的字符串苹果。
  • 这对我很有用,因为我希望我的对象是不可变的,所以不能选择虚拟构造函数。
  • 在我的情况下,它还需要在构造函数上添加@JsonCreator @JsonProperty
【解决方案4】:

当我遇到这个问题时,这是尝试使用内部类作为 DO 的结果。内部类的构造(静默)需要一个封闭类的实例——Jackson 无法使用它。

在这种情况下,将内部类移动到它自己的 .java 文件可以解决问题。

【讨论】:

  • 虽然将内部类移动到它自己的 .java 文件中是可行的,但添加 static 修饰符也可以解决@bludream 的答案中提到的问题。
【解决方案5】:

一般来说,出现这个错误是因为我们没有创建默认构造函数
但就我而言:
问题的出现只是因为我已经在父类中使用了对象类
这浪费了我一整天。

【讨论】:

  • 做嵌套类static就够了。
  • 使其成为静态对我有用。谢谢@sloth
【解决方案6】:

拇指规则:为您用作映射类的每个类添加一个默认构造函数。你错过了这个,问题就出现了!
只需添加默认构造函数,它应该可以工作。

【讨论】:

    【解决方案7】:

    你能测试一下这个结构吗?如果我没记错的话,你可以这样使用:

    {
        "applesRequest": {
            "applesDO": [
                {
                    "apple": "Green Apple"
                },
                {
                    "apple": "Red Apple"
                }
            ]
        }
    }
    

    其次,请为每个类添加默认构造函数,这也可能有所帮助。

    【讨论】:

    • 不工作:出现以下错误:“org.codehaus.jackson.map.exc.UnrecognizedPropertyException:无法识别的字段“applesRequest”(com.smartshop.dao.AllApplesDO 类),未标记为可忽略”
    • 以前它至少不会通过 AllApplesDO 的错误,并且只为封闭类抛出。现在它为第一个类本身抛出
    • 需要一个默认构造函数。谢谢!
    • 不应该选择这个作为正确答案吗?
    【解决方案8】:

    您必须在我们的模型类中创建虚拟的空构造函数。所以在映射 json 时,它通过 setter 方法设置。

    【讨论】:

    • 这是解决办法。
    • 我也是这样。我的对象有许多不同的构造函数,所以我只创建了另一个显然被杰克逊使用的空构造函数。
    【解决方案9】:

    关于上次发布的问题,我在使用 Lombok 1.18.* 时遇到了同样的问题。

    我的解决方案是添加@NoArgsConstructor(不带参数的构造器),因为@Data 默认包含@RequiredArgsConstructor(带参数的构造器)。

    lombok 文档 https://projectlombok.org/features/all

    这样就解决了问题:

    package example.counter;
    
    import javax.validation.constraints.NotNull;
    
    import lombok.Data;
    
    @Data
    @NoArgsConstructor
    public class CounterRequest {
        @NotNull
        private final Integer int1;
    
        @NotNull
        private final Integer int2;
    }
    

    【讨论】:

      【解决方案10】:

      如果开始注解构造函数,则必须注解所有字段。

      注意,我的 Staff.name 字段映射到 JSON 字符串中的“ANOTHER_NAME”。

           String jsonInString="{\"ANOTHER_NAME\":\"John\",\"age\":\"17\"}";
           ObjectMapper mapper = new ObjectMapper();
           Staff obj = mapper.readValue(jsonInString, Staff.class);
           // print to screen
      
           public static class Staff {
             public String name;
             public Integer age;
             public Staff() {         
             }        
      
             //@JsonCreator - don't need this
             public Staff(@JsonProperty("ANOTHER_NAME") String   n,@JsonProperty("age") Integer a) {
              name=n;age=a;
             }        
          }
      

      【讨论】:

        【解决方案11】:

        您必须了解 Jackson 有哪些可用于反序列化的选项。在 Java 中,方法参数名称不存在于编译代码中。这就是为什么 Jackson 通常不能使用构造函数来创建一个已经设置好的对象。

        所以,如果有一个空的构造函数并且还有setter,它使用空的构造函数和setter。如果没有 setter,则使用一些黑暗魔法(反射)来完成。

        如果您想对 Jackson 使用构造函数,则必须使用 @PiersyP 在他的回答中提到的注释。您还可以使用构建器模式。如果遇到一些异常,祝你好运。 Jackson 中的错误处理非常耗时,很难理解错误消息中的胡言乱语。

        【讨论】:

        • 您需要“默认无参数构造函数”FooClass() 的原因可能是因为 Spring 遵循 JavaBean 规范,这要求它在序列化和反序列化对象时自动编组和解组。
        • 好吧,无论如何,Java 序列化和反序列化为二进制流并不是问题所在。因此,Jackson 提供多种模式用于反序列化是一件好事。我特别喜欢构建器模式,因为它允许生成的对象是不可变的。
        【解决方案12】:

        为所有实体类添加默认构造函数

        【讨论】:

          【解决方案13】:

          自定义杰克逊序列化器/反序列化器失败也可能是问题所在。虽然不是你的情况,但值得一提。

          我遇到了同样的例外情况。

          【讨论】:

            【解决方案14】:

            对我来说,这曾经有效,但升级库导致出现此问题。问题是有这样的课程:

            package example.counter;
            
            import javax.validation.constraints.NotNull;
            
            import lombok.Data;
            
            @Data
            public class CounterRequest {
                @NotNull
                private final Integer int1;
            
                @NotNull
                private final Integer int2;
            }
            

            使用龙目岛:

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.0</version>
            </dependency>
            

            回到

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.10</version>
            </dependency>
            

            解决了这个问题。不知道为什么,但想记录下来以备将来使用。

            【讨论】:

              猜你喜欢
              • 2016-09-28
              • 1970-01-01
              • 2015-04-19
              • 1970-01-01
              • 2015-06-26
              • 2015-09-14
              • 1970-01-01
              • 1970-01-01
              • 2012-06-06
              相关资源
              最近更新 更多