JsonMappingException:未找到类型[简单类型,类]的合适构造函数:无法从JSON对象实例化


437

尝试获取JSON请求并处理它时出现以下错误:

org.codehaus.jackson.map.JsonMappingException:没有找到适合类型[简单类型,类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 Framework。

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


2
我在上面的代码中没有看到任何子类,这个代码是您的尝试还是您在组成一个更简单的示例?
gkamal 2011年

我添加了一个答案,并对其工作方式进行了更多解释。基本上,您需要认识到Java不会在运行时保留方法参数名称。
Vlasec

Answers:


565

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

实际上问题出在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的新手。
andho 2013年

181
您可以将jackson与内部(嵌套)类一起使用,在这种情况下,序列化就可以了。唯一的绊脚石是内部类必须标记为“静态”,以便反序列化正常工作。看到此处的感叹:cowtowncoder.com/blog/archives/2010/08/entry_411.html
jpennell

3
有人可以解释为什么会这样吗?我有一个非常类似的错误。以为所有正确的构造函数都已经到位,但无法反序列化。阅读这篇文章后,只有在我添加了虚拟构造函数之后,它才起作用。
user8658912 2014年

6
@Suman我不会将其称为虚拟构造函数-它只是默认的构造函数。它不仅是完全有效的,而且是许多Java bean类型处理所必需的。(当然,它使我绊倒了。:
fool4jesus 2015年

2
如果您不想添加默认构造函数(例如,当您处理不可变对象时)。您将必须使用JsonCreator注释来告诉使用哪个构造函数或工厂方法来实例化对象。
拉胡尔

375

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

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

    private static class Condition {  //jackson specific    
    }
  2. 可能是您的类中没有默认的构造函数(更新:事实并非如此)

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


95
静态类对我的情况有所不同。谢谢!
jalogar 2014年

3
当然,你并不需要声明一个空的,无参数的默认构造函数,Java的会为你!(只要您不定义任何其他构造函数。)
Jonik

1
@Jonik,对!我的答案是旧的,如果我记得正确的话,由于杰克逊使用反射来到达内部类,所以我想需要定义默认的构造函数(在较新的版本中也可能不是这种情况),但是由于我没有确定你是正确的。
阿塞拉法蒂

6
是的,我的经验是使用Jackson 2.4.4:确实Java的隐式默认构造函数就足够了。当定义了其他确实接受参数的构造函数时(即Java不会为您生成noargs时),需要显式地编写no-args构造函数。
Jonik 2015年

2
同样和我在一起,静态课堂节省了一天的时间。
西蒙(Simon)

58

我想为此添加另一个不需要虚拟构造函数的解决方案。由于虚拟构造函数有些混乱,因此会造成混乱。我们可以提供一个安全的构造函数,并通过注释构造函数参数,允许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) {
        }

}

此解决方案成功了。我只想提及以下内容,我有一个构造函数,但是参数的名称与实例参数的名称不同,因此无法进行映射。添加注释可以解决该问题,但是重命名参数也可能会起作用。
Fico

如果构造函数参数不在响应中怎么办?可以通过其他方式注入吗?
Eddie Jaoude 2015年

正在被送到这里的唯一显著数据是字符串苹果认为响应。
PiersyP 2015年

1
这对我很有用,因为我希望对象是不可变的,因此不能使用虚拟构造函数。
乔纳森·铂拉诺

就我而言,它还需要在@JsonCreator上加上@JsonProperty
m1ld

31

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

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


6
尽管将内部类移至其自己的.java文件有效,但添加静态修饰符也可以解决@bludream的答案中提到的问题。
jmarks 2016年

20

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


创建嵌套类就足够了static
懒惰

13

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


很好的答案。谢谢。保存我的一天。
史蒂夫,

9

你能测试一下这个结构吗?如果我没记错,您可以通过以下方式使用它:

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

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


无法正常运作:出现以下错误:“ org.codehaus.jackson.map.exc.UnrecognizedPropertyException:无法识别的字段“ applesRequest”(com.smartshop.dao.AllApplesDO类),未标记为可忽略”
Lucky Murari,

以前,它过去对于AllApplesDO至少不会出错,并且仅对封闭类进行抛出。.现在,它对第一类本身进行抛出
Lucky Murari

需要一个默认的构造函数。谢谢!
Planky

难道不应该选择这个作为正确答案吗?
快速齿

7

您必须在模型类中创建一个虚拟的空构造函数,因此在映射json时,它是通过setter方法设置的。


这就是解决方法。
David Kobia

对我来说也是如此。我的对象有许多不同的构造函数,所以我只是创建了另一个空的,显然供杰克逊使用。
亚历山德罗·罗阿罗

5

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

请注意,我的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;
       }        
    }

4

您必须了解Jackson可以进行反序列化的选项。在Java中,方法参数名称不存在于已编译的代码中。因此,Jackson通常无法使用构造函数来创建一个定义完好的对象,并且已经设置了所有对象。

因此,如果有一个空的构造函数并且也有一些setter,那么它将使用该空的构造函数和setter。如果没有二传手,可以使用一些黑魔法(反射)来做。

如果要在Jackson上使用构造函数,则必须使用@PiersyP在其答案中提到的注释。您也可以使用构建器模式。如果遇到一些例外,祝您好运。Jackson的错误处理时间很长,很难理解错误消息中的乱码。


您之所以需要“默认无参数构造函数” FooClass()的原因,可能是因为Spring遵循JavaBean规范,该规范要求该规范可用于在序列化和反序列化对象时自动进行编组和解组。
原子88

嗯,无论如何,Java序列化和反序列化为二进制流并不是问题所在。因此,Jackson提供多种用于反序列化的模式是很好的。我特别喜欢构建器模式,因为它允许生成的对象是不可变的。
Vlasec

2

关于上一份出版物,在使用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;
}


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

使用龙目岛:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.