JsonMappingException: не найдено подходящего конструктора для типа [simple type, class]: невозможно создать экземпляр из объекта JSON

Я получаю следующую ошибку при попытке получить запрос JSON и обработать его:

org.codehaus.jackson.map.JsonMappingException: не найдено подходящего конструктора для типа [simple type, class 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
    }
}

Я думаю, что Джексон не может преобразовать JSON в объекты Java для подклассов. Пожалуйста, помогите с параметрами конфигурации для Jackson для преобразования JSON в объекты Java. Я использую Spring Framework.

EDIT: Включена основная ошибка, вызывающая эту проблему в вышеприведенном классе образцов. Пожалуйста, просмотрите принятый ответ для решения.

Ответ 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() {
    }

}

Ответ 2

Это происходит по следующим причинам:

  1. Ваш внутренний класс должен быть определен как статический

    private static class Condition {  //jackson specific    
    }
    
  2. Возможно, в вашем классе нет конструктора по умолчанию (UPDATE: похоже, это не так)

    private static class Condition {
        private Long id;
    
        public Condition() {
        }
    
        // Setters and Getters
    }
    
  3. Это может быть ваши сеттеры не определены должным образом или не видны (например, частный сеттер)

Ответ 3

Я хотел бы добавить еще одно решение для этого, которое не требует конструктора-заглушки. Поскольку конструкторы-заглушки немного запутаны и впоследствии запутываются. Мы можем предоставить безопасный конструктор и аннотируя аргументы конструктора, мы разрешаем 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) {
        }

}

Ответ 4

Когда я столкнулся с этой проблемой, это было результатом попытки использовать внутренний класс для выполнения DO. Построение внутреннего класса (тихо) требовало экземпляра охватывающего класса, который не был доступен Джексону.

В этом случае перемещение внутреннего класса в собственный .java файл устраняет проблему.

Ответ 5

Как правило, эта ошибка возникает из-за того, что мы не делаем конструктор по умолчанию, но в моем случае проблема возникла только из-за того, что я использовал использованный класс объекта внутри родительского класса. Это потратило впустую весь мой день.

Ответ 6

Правило Thumb. Добавьте конструктор по умолчанию для каждого класса, который вы использовали в качестве класса сопоставления. Вы пропустили это и возникли проблемы!
Просто добавьте конструктор по умолчанию и он должен работать.

Ответ 7

Можете ли вы проверить эту структуру. Если я правильно помню, вы можете использовать его следующим образом:

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

Во-вторых, добавьте конструктор по умолчанию в каждый класс, который он также может помочь.

Ответ 8

Вам нужно создать пустой конструктор в нашем классе модели. Поэтому при сопоставлении json он устанавливается методом setter.

Ответ 9

Если вы начинаете аннотировать конструктор, вы должны аннотировать все поля.

Обратите внимание: мое поле Staff.name отображается в "ANOTHER_NAME" в строке 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;
       }        
    }

Ответ 10

Вы должны понять, какие варианты есть у Джексона для десериализации. В Java имена аргументов метода отсутствуют в скомпилированном коде. Вот почему Джексон не может вообще использовать конструкторы для создания четко определенного объекта со всем уже установленным.

Таким образом, если есть пустой конструктор, а также есть сеттеры, он использует пустой конструктор и сеттеры. Если сеттеров нет, для этого используется некоторая темная магия (отражения).

Если вы хотите использовать конструктор с Джексоном, вы должны использовать аннотации, упомянутые @PiersyP в его ответе. Вы также можете использовать шаблон строителя. Если вы столкнулись с некоторыми исключениями, удачи. Обработка ошибок в Джексоне отстой, это трудно понять, что за ошибки в сообщениях об ошибках.

Ответ 11

Неудача пользовательских сериализаторов/десериализаторов Jackson также может быть проблемой. Хотя это не ваш случай, стоит упомянуть.

Я столкнулся с тем же исключением, и это было так.

Ответ 12

Для меня это работало, но обновление библиотек привело к появлению этой проблемы. Проблема в том, что у меня был такой класс:

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>

Исправлена проблема. Не уверен, почему, но хотел документировать это на будущее.

Ответ 13

Что касается последней публикации, у меня была та же проблема, когда использование 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;
}