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

Luc*_*ari 422 java spring json annotations jackson

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

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

这是我要发送的JSON:

{
  "applesDO" : [
    {
      "apple" : "Green Apple"
    },
    {
      "apple" : "Red Apple"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

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

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

AllApplesDO是ApplesDO的包装器:

public class AllApplesDO {

    private List<ApplesDO> applesDO;

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

    public void setApplesDO(List<ApplesDO> applesDO) {
        this.applesDO = applesDO;
    }
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为Jackson无法将JSON转换为子类的Java对象.请帮助Jackson将JSON转换为Java Objects的配置参数.我正在使用Spring Framework.

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

Luc*_*ari 551

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

实际上问题出在ApplesDO Class中:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

}
Run Code Online (Sandbox Code Playgroud)

  • 您可以将jackson与内部(嵌套)类一起使用,在这种情况下,序列化工作正常.唯一的绊脚石是必须将内部类标记为"静态"以便反序列化才能正常工作.请参阅此处的exlanation:http://cowtowncoder.com/blog/archives/2010/08/entry_411.html (177认同)
  • @Suman我不会称之为虚拟构造函数 - 它只是默认的构造函数.它不仅完全有效,而且是多种java bean类型处理所必需的.(当然,它让我绊倒了.:-)) (6认同)
  • 有人可以解释为什么会这样吗?我有一个非常类似的错误.认为所有正确的构造函数都已到位,但无法反序列化.只有在我读完这篇文章之后我才添加了一个虚拟构造函数. (3认同)
  • 如果您不想添加默认构造函数(例如,当您处理不可变对象时).您必须告诉使用哪个构造函数或工厂方法来使用JsonCreator注释来实例化对象. (2认同)

aze*_*ati 371

出现这种情况的原因如下:

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

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

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

  • 静态类在我的情况下有所不同.谢谢! (95认同)
  • 是的,我的经验是与Jackson 2.4.4:确实Java的隐式默认构造函数就足够了.如果你定义了*其他*构造函数,那么你需要显式地编写no-args构造函数**这些构造函数确实接受了参数(即当Java不为你生成no-args时). (5认同)
  • 当然,你**不需要声明一个空的,无参数的默认构造函数,[Java为你做的](http://docs.oracle.com/javase/specs/jls/se7/ HTML/JLS-8.html#JLS-8.8.9)!(只要您没有定义任何其他构造函数.) (3认同)
  • 还有我,静态类节省了一天. (2认同)

Pie*_*syP 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) {
        }

}
Run Code Online (Sandbox Code Playgroud)


jma*_*rks 31

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

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

  • 将内部类移动到自己的.java文件时,添加**static**修饰符也可以解决@ bludream的答案中提到的问题. (6认同)

alo*_*lok 17

一般来说,这错误出现,因为我们不作默认构造函数,但在我的情况的问题是未来不仅是因为我做了父类中使用的对象类.这浪费了我一整天.

  • 使嵌套类成为“static”就足够了。 (3认同)

Bad*_*dal 12

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


dan*_*nik 9

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

{
    "applesRequest": {
        "applesDO": [
            {
                "apple": "Green Apple"
            },
            {
                "apple": "Red Apple"
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

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


小智 6

关于上次发布,我遇到了同样的问题,使用 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;
}
Run Code Online (Sandbox Code Playgroud)


Vla*_*sec 5

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

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

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


Vor*_*tex 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;
       }        
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

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