JsonMappingException:找不到类型[simple type,class]的合适构造函数:无法从JSON对象实例化

时间:2011-10-02 10:16:13

标签: java json spring annotations jackson

尝试获取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对象。请帮助Jackson将JSON转换为Java Objects的配置参数。我正在使用Spring Framework。

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

14 个答案:

答案 0 :(得分:528)

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

实际上问题出在 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() {
    }

}

答案 1 :(得分:359)

出现以下原因:

  1. 您的内部类应定义为静态

    private static class Condition {  //jackson specific    
    }
    
  2. 您的班级可能没有默认构造函数(更新:似乎并非如此)

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

答案 2 :(得分:57)

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

所以以下内容也适用。请注意,注释中的字符串必须与字段名称匹配。

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) {
        }

}

答案 3 :(得分:29)

当我遇到这个问题时,这是尝试使用内部类作为DO的结果。构建内部类(默默地)需要一个封闭类的实例 - 杰克逊无法使用。

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

答案 4 :(得分:14)

通常会出现此错误,因为我们没有使用默认构造函数,但就我而言,问题仅是由于我在父类中使用了对象类。这浪费了我一整天。

答案 5 :(得分:11)

Thumb Rule :为您用作映射类的每个类添加默认构造函数。你错过了这个,问题就出现了! 只需添加默认构造函数即可。

答案 6 :(得分:10)

请测试一下这个结构。如果我记得没错,你可以这样使用它:

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

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

答案 7 :(得分:5)

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

答案 8 :(得分:4)

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

注意,我的Staff.name字段已映射到&#34; ANOTHER_NAME&#34;在JSON字符串中。

     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;
       }        
    }

答案 9 :(得分:3)

你必须意识到杰克逊有哪些选项可用于反序列化。在Java中,编译代码中不存在方法参数名称。这就是为什么杰克逊一般不能使用构造函数来创建一个定义良好的对象,并且已经设置了所有内容。

因此,如果有一个空构造函数并且还有setter,它使用空构造函数和setter。如果没有制定者,可以使用一些黑暗魔法(反射)来做它。

如果你想使用Jackson的构造函数,你必须在他的答案中使用@PiersyP提到的注释。您还可以使用构建器模式。如果你遇到一些例外,祝你好运。杰克逊的错误处理吸引了大量时间,很难理解错误信息中的乱码。

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

对我来说,这曾经有用,但升级库会导致出现此问题。问题是有这样一个类:

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;
}

使用lombok:

<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>

修正了问题。不确定原因,但希望将来记录下来。

答案 12 :(得分:0)

关于上一个出版物,在使用Lombok 1.18。*产生问题时,我遇到了同样的问题。

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

龙目岛文档 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;
}

答案 13 :(得分:0)

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