Создатели, как и конструкция по умолчанию, не существуют): невозможно десериализовать из значения объекта (нет Создателя на основе делегатов или свойств)

Я пытаюсь использовать API с помощью Retrofit и Jackson для десериализации. Я получаю сообщение об ошибке No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator.

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

Jayson Minard 08.11.2018 03:40

Пожалуйста, измените принятый ответ.

Noumenon 31.10.2020 06:21
150
2
253 943
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

Вам необходимо использовать jackson-module-kotlin для десериализации в классы данных. Подробнее см. здесь.

Приведенное выше сообщение об ошибке - это то, что Джексон дает вам, если вы пытаетесь десериализовать какое-то значение в класс данных, когда этот модуль не включен или, даже если это так, когда используемый ObjectMapper не имеет зарегистрированного KotlinModule. Например, возьмите этот код:

data class TestDataClass (val foo: String)

val jsonString = """{ "foo": "bar" }"""
val deserializedValue = ObjectMapper().readerFor(TestDataClass::class.java).readValue<TestDataClass>(jsonString)

Это приведет к ошибке со следующей ошибкой:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `test.SerializationTests$TestDataClass` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)

Если вы измените приведенный выше код и замените ObjectMapper на jacksonObjectMapper (который просто возвращает нормальный ObjectMapper с зарегистрированным KotlinModule), он работает. т.е.

val deserializedValue = jacksonObjectMapper().readerFor(TestDataClass::class.java).readValue<TestDataClass>(jsonString)

Я не уверен насчет Android, но похоже, что вам нужно заставить систему использовать jacksonObjectMapper для десериализации.

Обновили ответ с дополнительной информацией. Интересно, хотя у вас зарегистрирован модуль, код, выполняющий десериализацию, явно не использует jacksongObjectMapper? Я просто предполагаю, что это связано с этим, потому что сообщение об ошибке, которое вы получаете, - это именно то, что Джексон дает вам, когда этот объектный сопоставитель не используется.

Yoni Gibbs 07.11.2018 15:54

Могу я передать вам хранилище, чтобы вы посмотрели?

José Nobre 07.11.2018 15:58

Действуй. Хотя я никогда не делал ничего для Android, так что не надейтесь :-) Я просто ответил на это, потому что на днях я столкнулся именно с этой проблемой в каком-то серверном коде Kotlin.

Yoni Gibbs 07.11.2018 15:59

Проблема определенно связана с неиспользованием этого модуля и использованием класса данных. Итак, вам необходимо зарегистрировать модуль в картографе объектов, который используется системой. Найдите в своих фреймворках, которые вы используете, где вы можете изменить конфигурацию сопоставителя объектов для вызова mapper.registerModule(KotlinModule()) @jose

Jayson Minard 08.11.2018 03:42

Хосе и Джейсон пишут о json :-D

programaths 06.08.2019 14:54

Применимо ли это к приложениям, отличным от kotlin, т.е. приложениям Java 8?

Janac Meena 06.03.2020 17:30

@JanacMeena, решение в этом ответе относится к Kotlin, но сама ошибка потенциально может возникнуть при десериализации в классы Java, если они настроены определенным образом (например, может быть, только с частным конструктором или что-то в этом роде, я не пробовал, поэтому не уверен).

Yoni Gibbs 02.04.2020 08:38

Я использую Quarkus с Kotlin, а тело конечной точки rest api использует объект класса данных. Добавление jackson-module-kotlin решило проблему.

YazidEF 14.10.2021 03:17
Ответ принят как подходящий

Причина: Эта ошибка возникает из-за того, что библиотека Джексона не знает, как создать вашу модель, у которой нет пустого конструктора, а модель содержит конструктор с параметрами, которые не аннотировали свои параметры с помощью @JsonProperty("field_name"). По умолчанию компилятор java создает пустой конструктор, если вы не добавляли конструктор в свой класс.

Решение: Добавьте в модель пустой конструктор или аннотируйте параметры конструктора с помощью @JsonProperty("field_name").

Если вы используете класс данных Kotlin, вы также можете аннотировать с помощью @JsonProperty("field_name") или зарегистрировать модуль джексона котлин в ObjectMapper.

Вы можете создавать свои модели, используя http://www.jsonschema2pojo.org/.

Причина, по которой это работает, заключается в том, что они не являются классами данных.

mkki 03.08.2019 01:12

Это решение. Но какой способ лучше? Создание пустого конструктора вообще или добавление JSONproperty?

O. Schnieders 18.12.2020 20:41

@Maximus Я думаю, что нет разницы в производительности (если вы имеете в виду лучшую производительность). Создать пустой конструктор проще, чем добавлять аннотацию к каждому параметру.

Bek 19.12.2020 08:57

Что делать, если я не могу изменить класс, который пытаюсь десериализовать? Есть ли способ заставить это работать? Единственный вариант - настраиваемый десериализатор?

thomas.schuerger 24.06.2021 15:44

Что делать, если я не могу редактировать класс? Например, я хочу десериализовать Spring Pair. Могу ли я создать собственный метод десериализации вне класса Pair?

dpelisek 08.07.2021 12:44

Я знаю, что это старый пост, но для всех, кто использует Retrofit, это может быть полезно.

Если вы используете классы Retrofit + Jackson + Kotlin + Data, вам понадобятся:

  1. добавьте implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2' в свои зависимости, чтобы Джексон мог десериализоваться в классы данных
  2. При модернизации передайте Kotlin Jackson Mapper, чтобы в Retrofit использовался правильный картограф, например:
    val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()

    val retrofit = Retrofit.Builder()
          ...
          .addConverterFactory(JacksonConverterFactory.create(jsonMapper))
          .build()

Примечание. Если дооснащение не используется, у @Jayson Minard есть более общий подход.

большой! Я думаю, что при модернизации использовался другой экземпляр Джексона

Andres 14.05.2019 07:40

Хотел бы я дать вам несколько очков репутации, потому что вы спасли меня в последнюю минуту дополнительного времени !! Спасибо

d4c0d312 04.01.2020 04:48

Я попал сюда в поисках этой ошибки:

No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator

Ничего общего с Retrofit, но если вы используете Jackson, эта ошибка была решена путем добавления конструктора по умолчанию к классу, вызывающему ошибку. Подробнее здесь: https://www.baeldung.com/jackson-exception

Если вы хотите, чтобы ваш объект был неизменным, вам не нужно создавать конструктор по умолчанию. Добавление @JsonCreator или @ConstructorProperties({"prop1Name", "propr2Name"}) в конструктор решает указанную выше ошибку.

Kirill 30.11.2019 08:45

Если вы используете Lobok и @Data, убедитесь, что ваши поля не являются окончательными, иначе пустой конструктор невозможен. Так что это не работает: @Data static class LoginResponse { private final String token, message; private final int status; } Но это работает: @Data static class LoginResponse { private String token, message; private int status; }

Vladtn 27.12.2019 10:21

@Vladtn - спасибо, это была моя проблема; 0

a9120bb 17.09.2021 23:53

Если вы используете Unirest в качестве библиотеки http, использование GsonObjectMapper вместо JacksonObjectMapper также будет работать.

<!-- https://mvnrepository.com/artifact/com.konghq/unirest-object-mappers-gson -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-object-mappers-gson</artifactId>
    <version>2.3.17</version>
</dependency>
Unirest.config().objectMapper = GsonObjectMapper()

Я использую спасать с Kotlin и решил его с помощью @ConstructorProperties

    data class MyResponse @ConstructorProperties("message", "count") constructor(
        val message: String,
        val count: Int
    )

Джексон использует @ConstructorProperties. Это также должно исправить Lombok @Data.

Это единственное решение, которое работает для меня в ситуации aws lambda + kotlin.

GJ. 04.05.2021 04:14

Если вы используете Ломбок на POJO модель, убедитесь, что у вас есть эти аннотации:

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor

Он может отличаться, но убедитесь, что @Getter и особенно @NoArgsConstructor.

@NoArgsConstructor решил мою ситуацию. Мои полные аннотации - @Data @AllArgsConstructor @NoArgsConstructor @Entity @JsonInclude(Include.NON_DEFAULT)
davide 20.02.2020 16:35
@Data эквивалентен @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode, так что может быть нужен только @NoArgsConstructor
54l3d 06.03.2020 15:34

@ 54l3d @Data не будет включать @RequiredArgsConstructor, если вы укажете другую аннотацию конструктора вместе с ней.

payne 16.04.2020 16:56

Просто хотел указать, что вы спасли мне день :), все это время мне не хватало аннотации @NoArgsConstructor.

Pol Ortiz 20.04.2020 14:09

У меня была аналогичная проблема (с использованием Jackson, lombok, gradle) и POJO без конструктора args - решение заключалось в том, чтобы добавить

lombok.anyConstructor.addConstructorProperties=true

в файл lombok.config

Когда вы используете Lombok builder, вы получите указанную выше ошибку.

 @JsonDeserialize(builder = StationResponse.StationResponseBuilder.class)
 public class StationResponse{
   //define required properties 
 }     

 @JsonIgnoreProperties(ignoreUnknown = true)
 @JsonPOJOBuilder(withPrefix = "")
 public static class StationResponseBuilder {}

Ссылка: https://projectlombok.org/features/Builder с Джексоном

Как упоминалось в ошибке, у класса нет конструктора по умолчанию.

Добавление @NoArgsConstructor в класс сущности должно исправить это.

Я мог бы решить эту проблему в Kotlin с помощью аннотации @JacksonProperty. Пример использования для вышеуказанного случая:

import com.fasterxml.jackson.annotation.JsonProperty
...
data class Station(
     @JacksonProperty("repsol_id") val repsol_id: String,
     @JacksonProperty("name") val name: String,
...

Расширяя ответ Йони Гиббса, если вы находитесь в проекте Android с использованием модернизации и настройки сериализации с помощью Джексона, вы можете сделать эти вещи, чтобы десериализация работала должным образом с классом данных kotlin.

В вашем импорте Gradle сборки:

implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.11.+"

Затем ваша реализация модернизации:

val serverURL = "http://localhost:8080/api/v1"

val objectMapper = ObjectMapper()
objectMapper.registerModule(KotlinModule())
//Only if you are using Java 8's Time API too, require jackson-datatype-jsr310
objectMapper.registerModule(JavaTimeModule())

Retrofit.Builder()
    .baseUrl(serverURL)
    .client(
        OkHttpClient.Builder()
           .readTimeout(1, TimeUnit.MINUTES)//No mandatory
            .connectTimeout(1, TimeUnit.MINUTES)//No mandatory
            .addInterceptor(UnauthorizedHandler())//No mandatory
            .build())
    .addConverterFactory(
                JacksonConverterFactory.create(objectMapper)
            )
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build()

Класс данных:

@JsonIgnoreProperties(ignoreUnknown = true)
data class Task(val id: Int,
                val name: String,
                @JsonSerialize(using = LocalDateTimeSerializer::class)
                @JsonDeserialize(using = LocalDateTimeDeserializer::class)
                val specificDate: LocalDateTime?,
                var completed: Boolean,
                val archived: Boolean,
                val taskListId: UUID?

Я использую Spring + Kotlin для Backend, и я решил эту проблему с помощью KotlinModule (), спасибо.

Caio 15.07.2020 00:24

Я решил эту проблему, добавив ограничитель без аргументов. Если вы используете Ломбок, вам нужно только добавить аннотацию @NoArgsConstructor:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
public class User {
    private Long userId;
    private String shortName;
}

Просто хочу отметить, что этот отвечать дает лучшее объяснение. Обычно вы можете использовать @Getter и @NoArgConstructor вместе. или пусть Lombok регенерирует @ConstructorProperties, используя файл lombok.config,
или скомпилируйте свой Java-проект с флагами -parameters,
или позвольте Джексону использовать @Builder Ломбока

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

@Configuration
open class JacksonMapper {

    @Bean
    open fun mapper(): ObjectMapper {
        val mapper = ObjectMapper()
        ...

        mapper.registerModule(KotlinModule())
        return mapper
    }
}

Моя причина проблемы кажется мне очень необычной, я не уверен, что кто-то еще получает ошибку при том же состоянии, я нашел причину, сравнив предыдущие коммиты, вот и все:

Через мой build.gradle я использовал эти 2 параметра компилятора, и комментирование этой строки устранило проблему.

//compileJava.options.compilerArgs = ['-Xlint:unchecked','-Xlint:deprecation']

Если вы используете LOMBOK. Создайте файл lombok.config, если у вас его нет, и добавьте эту строку.

lombok.anyconstructor.addconstructorproperties=true

Обнаружена та же ошибка в приведенном ниже сценарии использования.

Я попытался попасть в конечную точку Rest (Put mapping), используя загрузку спринта (2.0.0 Версия моментального снимка), не имея конструктора дефолт в соответствующем bean-компоненте.

Но с последними версиями Spring Boot (2.4.1 Версия) тот же фрагмент кода работает без ошибок.

поэтому конструктор bean-компонента по умолчанию - больше никогда, необходимый в последней версии Spring Boot

Просто нужно добавить @NoArgsConstructor и все работает.

Я получил ту же ошибку, и проблема заключалась в том, что мой модель не реализовал Сериализуемый, поэтому проверьте и это, может помочь, поскольку это тоже одна из причин.

Добавить конструктор в класс ИЛИ если вы используете pojo add @NoArgsConstructor @AllArgsConstructor

Также включите JsonProperty - @JsonProperty("name") private List<Employee> name;

Ответ Бека правильный.

Но в случае, если кто-то пытается использовать неизменяемый класс в restcontroller, то есть они используют @value lombok, вам нужно добавить lombok.anyConstructor.addConstructorProperties=true

Вы можете создать файл с именем lombok.config в том же месте, где находится корневой pom.xml, и добавить эту строку в файл

https://stackoverflow.com/a/56022839/6700081

У меня такая же ошибка, и после того, как я добавил конструктор без параметров, проблема была решена.

Будьте осторожны с Lombok, особенно с @Builder.

Что исправило проблему для меня:

   @JsonDeserialize(builder = X.XBuilder.class)
       class X{
          @JsonPOJOBuilder(withPrefix = "")
          public static class XBuilder{

          }
}

Я надеюсь это облегчит твою жизнь

Я использую Quarkus, Jackson и Lombok. Итак, я решил эту проблему, добавив атрибут @Jacksonized в класс модели. Итак, все атрибуты:

@Jacksonized //missing
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ...

Другие вопросы по теме