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

发布于 2024-12-07 18:50:22 字数 1331 浏览 0 评论 0原文

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

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

这是我的JSON尝试发送:

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

在控制器中,我有以下方法签名:

@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 对象。我正在使用 Spring 框架。

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

I am getting the following error when trying to get a JSON request and process it:

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class com.myweb.ApplesDO]: can not instantiate from JSON object (need to add/enable type information?)

Here is the JSON I am trying to send:

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

In Controller, I have the following method signature:

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

AllApplesDO is a wrapper of 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
    }
}

I think that Jackson is unable to convert JSON into Java objects for subclasses. Please help with the configuration parameters for Jackson to convert JSON into Java Objects. I am using Spring Framework.

EDIT: Included the major bug that is causing this problem in the above sample class - Please look accepted answer for solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

记忆で 2024-12-14 18:50:22

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

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

}

So, finally I realized what the problem is. It is not a Jackson configuration issue as I doubted.

Actually the problem was in 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
    }
}

There was a custom constructor defined for the class making it the default constructor. Introducing a dummy constructor has made the error to go away:

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

}
花之痕靓丽 2024-12-14 18:50:22

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

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

    private static class Condition { //杰克逊特定    
    }
    
  2. 这可能是你的类中没有默认构造函数(更新:这似乎事实并非如此)

    私有静态类条件{
        私人长ID;
    
        公共条件(){
        }
    
        // 设置器和获取器
    }
    
  3. 可能是您的 Setter 定义不正确或不可见(例如私有设置器)

This happens for these reasons:

  1. your inner class should be defined as static

    private static class Condition {  //jackson specific    
    }
    
  2. It might be that you got no default constructor in your class (UPDATE: This seems not to be the case)

    private static class Condition {
        private Long id;
    
        public Condition() {
        }
    
        // Setters and Getters
    }
    
  3. It could be your Setters are not defined properly or are not visible (e.g. private setter)

一杯敬自由 2024-12-14 18:50:22

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

所以下面的方法也可以工作。请注意,注释内的字符串必须与字段名称匹配。

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

}

I would like to add another solution to this that does not require a dummy constructor. Since dummy constructors are a bit messy and subsequently confusing. We can provide a safe constructor and by annotating the constructor arguments we allow jackson to determine the mapping between constructor parameter and field.

so the following will also work. Note the string inside the annotation must match the field name.

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

}
榆西 2024-12-14 18:50:22

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

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

When I ran into this problem, it was a result of trying to use an inner class to serve as the DO. Construction of the inner class (silently) required an instance of the enclosing class -- which wasn't available to Jackson.

In this case, moving the inner class to its own .java file fixed the problem.

时常饿 2024-12-14 18:50:22

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

Generally, this error comes because we don’t make default constructor.
But in my case:
The issue was coming only due to I have made used object class inside parent class.
This has wasted my whole day.

尐偏执 2024-12-14 18:50:22

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

Thumb Rule: Add a default constructor for each class you used as a mapping class. You missed this and issue arise!
Simply add default constructor and it should work.

温柔戏命师 2024-12-14 18:50:22

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

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

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

Can you please test this structure. If I remember correct you can use it this way:

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

Second, please add default constructor to each class it also might help.

‖放下 2024-12-14 18:50:22

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

You have to create dummy empty constructor in our model class.So while mapping json, it set by setter method.

仅一夜美梦 2024-12-14 18:50:22

关于上一篇文章,我遇到了同样的问题,即使用 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;
}

Regarding the last publication I had the same problem where using Lombok 1.18.* generated the problem.

My solution was to add @NoArgsConstructor (constructor without parameters), since @Data includes by default @RequiredArgsConstructor (Constructor with parameters).

lombok Documentation
https://projectlombok.org/features/all

That would solve the problem:

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;
}
动次打次papapa 2024-12-14 18:50:22

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

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

If you start annotating constructor, you must annotate all fields.

Notice, my Staff.name field is mapped to "ANOTHER_NAME" in JSON string.

     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;
       }        
    }
治碍 2024-12-14 18:50:22

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

因此,如果有一个空构造函数并且还有 setter,那么它会使用空构造函数和 setter。如果没有设定器,则使用一些黑魔法(反射)来做到这一点。

如果您想在 Jackson 中使用构造函数,则必须使用 @PiersyP 在其答案中提到的注释。您还可以使用构建器模式。如果您遇到一些异常,祝您好运。 Jackson 中的错误处理很糟糕,很难理解错误消息中的乱码。

You must realize what options Jackson has available for deserialization. In Java, method argument names are not present in the compiled code. That's why Jackson can't generally use constructors to create a well-defined object with everything already set.

So, if there is an empty constructor and there are also setters, it uses the empty constructor and setters. If there are no setters, some dark magic (reflections) is used to do it.

If you want to use a constructor with Jackson, you must use the annotations as mentioned by @PiersyP in his answer. You can also use a builder pattern. If you encounter some exceptions, good luck. Error handling in Jackson sucks big time, it's hard to understand that gibberish in error messages.

过度放纵 2024-12-14 18:50:22

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

Add default constructors to all the entity classes

半透明的墙 2024-12-14 18:50:22

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

我遇到了同样的例外,情况就是如此。

Failing custom jackson Serializers/Deserializers could also be the problem. Though it's not your case, it's worth mentioning.

I faced the same exception and that was the case.

记忆里有你的影子 2024-12-14 18:50:22

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

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>

修复问题。不知道为什么,但想记录下来以供将来使用。

For me, this used to work, but upgrading libraries caused this issue to appear. Problem was having a class like this:

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

Using lombok:

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

Falling back to

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

Fixed the issue. Not sure why, but wanted to document it for future.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文