Я пытаюсь использовать API с помощью Retrofit и Jackson для десериализации. Я получаю сообщение об ошибке No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator.
Пожалуйста, измените принятый ответ.
Вам необходимо использовать 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? Я просто предполагаю, что это связано с этим, потому что сообщение об ошибке, которое вы получаете, - это именно то, что Джексон дает вам, когда этот объектный сопоставитель не используется.
Могу я передать вам хранилище, чтобы вы посмотрели?
Действуй. Хотя я никогда не делал ничего для Android, так что не надейтесь :-) Я просто ответил на это, потому что на днях я столкнулся именно с этой проблемой в каком-то серверном коде Kotlin.
Проблема определенно связана с неиспользованием этого модуля и использованием класса данных. Итак, вам необходимо зарегистрировать модуль в картографе объектов, который используется системой. Найдите в своих фреймворках, которые вы используете, где вы можете изменить конфигурацию сопоставителя объектов для вызова mapper.registerModule(KotlinModule()) @jose
Хосе и Джейсон пишут о json :-D
Применимо ли это к приложениям, отличным от kotlin, т.е. приложениям Java 8?
@JanacMeena, решение в этом ответе относится к Kotlin, но сама ошибка потенциально может возникнуть при десериализации в классы Java, если они настроены определенным образом (например, может быть, только с частным конструктором или что-то в этом роде, я не пробовал, поэтому не уверен).
Я использую Quarkus с Kotlin, а тело конечной точки rest api использует объект класса данных. Добавление jackson-module-kotlin решило проблему.
Причина: Эта ошибка возникает из-за того, что библиотека Джексона не знает, как создать вашу модель, у которой нет пустого конструктора, а модель содержит конструктор с параметрами, которые не аннотировали свои параметры с помощью @JsonProperty("field_name"). По умолчанию компилятор java создает пустой конструктор, если вы не добавляли конструктор в свой класс.
Решение:
Добавьте в модель пустой конструктор или аннотируйте параметры конструктора с помощью @JsonProperty("field_name").
Если вы используете класс данных Kotlin, вы также можете аннотировать с помощью @JsonProperty("field_name") или зарегистрировать модуль джексона котлин в ObjectMapper.
Вы можете создавать свои модели, используя http://www.jsonschema2pojo.org/.
Причина, по которой это работает, заключается в том, что они не являются классами данных.
Это решение. Но какой способ лучше? Создание пустого конструктора вообще или добавление JSONproperty?
@Maximus Я думаю, что нет разницы в производительности (если вы имеете в виду лучшую производительность). Создать пустой конструктор проще, чем добавлять аннотацию к каждому параметру.
Что делать, если я не могу изменить класс, который пытаюсь десериализовать? Есть ли способ заставить это работать? Единственный вариант - настраиваемый десериализатор?
Что делать, если я не могу редактировать класс? Например, я хочу десериализовать Spring Pair. Могу ли я создать собственный метод десериализации вне класса Pair?
Я знаю, что это старый пост, но для всех, кто использует Retrofit, это может быть полезно.
Если вы используете классы Retrofit + Jackson + Kotlin + Data, вам понадобятся:
implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2' в свои зависимости, чтобы Джексон мог десериализоваться в классы данных val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()
val retrofit = Retrofit.Builder()
...
.addConverterFactory(JacksonConverterFactory.create(jsonMapper))
.build()
Примечание. Если дооснащение не используется, у @Jayson Minard есть более общий подход.
большой! Я думаю, что при модернизации использовался другой экземпляр Джексона
Хотел бы я дать вам несколько очков репутации, потому что вы спасли меня в последнюю минуту дополнительного времени !! Спасибо
Я попал сюда в поисках этой ошибки:
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"}) в конструктор решает указанную выше ошибку.
Если вы используете 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 - спасибо, это была моя проблема; 0
Если вы используете 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.
Если вы используете Ломбок на POJO модель, убедитесь, что у вас есть эти аннотации:
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
Он может отличаться, но убедитесь, что @Getter и особенно @NoArgsConstructor.
@NoArgsConstructor решил мою ситуацию. Мои полные аннотации - @Data @AllArgsConstructor @NoArgsConstructor @Entity @JsonInclude(Include.NON_DEFAULT)@Data эквивалентен @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode, так что может быть нужен только @NoArgsConstructor@ 54l3d @Data не будет включать @RequiredArgsConstructor, если вы укажете другую аннотацию конструктора вместе с ней.
Просто хотел указать, что вы спасли мне день :), все это время мне не хватало аннотации @NoArgsConstructor.
У меня была аналогичная проблема (с использованием 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 (), спасибо.
Я решил эту проблему, добавив ограничитель без аргументов. Если вы используете Ломбок, вам нужно только добавить аннотацию @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, и добавить эту строку в файл
Будьте осторожны с 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 ...
Похоже, вы не используете модуль Джексона для Kotlin, который работает с классами данных, у которых нет конструктора по умолчанию, в отличие от вашего. Ознакомьтесь с этим модулем и посмотрите, не возникнут ли у вас проблемы после этого.