Создатели, такие как конструкция по умолчанию, не существуют: не могут десериализоваться из значения объекта (нет delegate- или создателя на основе свойств).
Я пытаюсь использовать API, используя модификацию и Джексона для десериализации. Ошибка, присутствующая в заголовке "Создатели отсутствуют, как и конструкция по умолчанию, существует): невозможно десериализовать из значения объекта (нет delegate- или создателя на основе свойств" в onFailure.
Это JSON, который я хочу получить:
{
"data": {
"repsol_id": "1129",
"name": "ES-MASSAMÁ",
"latitude": "38.763733333",
"longitude": "-9.258619444000001",
"address": "RUA GENERAL HUMBERTO DELGADO, LT.16",
"post_code": "2745-280",
"location": "QUELUZ",
"service_store": 1,
"service_mechanical_workshop": 0,
"service_restaurant": 0,
"service_wash": 1
}
}
Это мой HomeFragment:
onCreate(){
viewModel.retrieveStation().observe(this, Observer {
dataBinding.favouriteStationTxt.text = it.name
})
}
Это моя модель представления:
class HomeViewModel @Inject constructor(
private val stationRepository: StationRepository
) : ViewModel() {
private val station = MutableLiveData<Station>()
fun retrieveStation():LiveData<Station> = station
fun loadStations(stationId:Int){
stationRepository.getStationFromId(stationId,{ station.postValue(it)},{})
}
}
Это мой репозиторий:
class StationRepository @Inject constructor(var apiManager: ApiManager) {
fun getStationFromId(stationId:Int,onSuccess: (Station)->Unit, onError: (Exception)->Unit){
apiManager.getStation(stationId, onSuccess,onError)
}
}
Это мой менеджер API (который объединяет несколько менеджеров API)
class ApiManager @Inject constructor(
private val stationsApiManager: StationsApiManager,
){
fun getStation(stationId: Int, onSuccess: (Station)->Unit, onFailure: (e: Exception)->Unit){
stationsApiManager.getStation(stationId,{onSuccess(it.data.toDomain())},onFailure)
}
}
Это мой StationAPiManager
class StationsApiManager @Inject constructor(private val stationApiService: StationsApiService){
fun getStation(stationId: Int, onSuccess: (StationResponse)->Unit, onFailure: (e: Exception)->Unit){
stationApiService.getStation(stationId).enqueue(request(onSuccess, onFailure))
}
private fun <T> request(onSuccess: (T)->Unit, onFailure: (e: Exception)->Unit)= object : Callback<T> {
override fun onFailure(call: Call<T>, t: Throwable) {
Log.d("error",t.message)
onFailure(Exception(t.message))
}
override fun onResponse(call: Call<T>, response: Response<T>) {
Log.d("Success",response.body().toString())
if(response.isSuccessful && response.body() != null) onSuccess(response.body()!!)
else
onFailure(Exception(response.message()))
}
}
}
Это мой STationsApiService (базовый URL в вариантах)
@GET("{station_id}")
fun getStation(@Path("station_id") stationId: Int): Call<StationResponse>
Это мой StationResponse
class StationResponse (
@JsonProperty("data")
val data: Station)
Это моя модель станции
data class Station(
val repsol_id: String,
val name: String,
val latitude: String,
val longitude: String,
val address: String,
val post_code: String,
val location: String,
val service_store: Boolean,
val service_mechanical_workshop: Boolean,
val service_restaurant: Boolean,
val service_wash: Boolean
)
Это мои DataMappers:
import com.repsol.repsolmove.network.movestationsapi.model.Station as apiStation
fun apiStation.toDomain() = Station(
repsol_id.toInt(),
name,
latitude.toDouble(),
longitude.toDouble(),
address,
post_code,
location,
service_store,
service_mechanical_workshop,
service_restaurant,
service_wash
)
Ответы
Ответ 1
Попробуйте ниже модели. Я использовал http://www.jsonschema2pojo.org/ для создания этих моделей.
StationResponse.java
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"data"
})
public class StationResponse {
@JsonProperty("data")
private Data data;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonProperty("data")
public Data getData() {
return data;
}
@JsonProperty("data")
public void setData(Data data) {
this.data = data;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
Data.java
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"repsol_id",
"name",
"latitude",
"longitude",
"address",
"post_code",
"location",
"service_store",
"service_mechanical_workshop",
"service_restaurant",
"service_wash"
})
public class Data {
@JsonProperty("repsol_id")
private String repsolId;
@JsonProperty("name")
private String name;
@JsonProperty("latitude")
private String latitude;
@JsonProperty("longitude")
private String longitude;
@JsonProperty("address")
private String address;
@JsonProperty("post_code")
private String postCode;
@JsonProperty("location")
private String location;
@JsonProperty("service_store")
private Integer serviceStore;
@JsonProperty("service_mechanical_workshop")
private Integer serviceMechanicalWorkshop;
@JsonProperty("service_restaurant")
private Integer serviceRestaurant;
@JsonProperty("service_wash")
private Integer serviceWash;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonProperty("repsol_id")
public String getRepsolId() {
return repsolId;
}
@JsonProperty("repsol_id")
public void setRepsolId(String repsolId) {
this.repsolId = repsolId;
}
@JsonProperty("name")
public String getName() {
return name;
}
@JsonProperty("name")
public void setName(String name) {
this.name = name;
}
@JsonProperty("latitude")
public String getLatitude() {
return latitude;
}
@JsonProperty("latitude")
public void setLatitude(String latitude) {
this.latitude = latitude;
}
@JsonProperty("longitude")
public String getLongitude() {
return longitude;
}
@JsonProperty("longitude")
public void setLongitude(String longitude) {
this.longitude = longitude;
}
@JsonProperty("address")
public String getAddress() {
return address;
}
@JsonProperty("address")
public void setAddress(String address) {
this.address = address;
}
@JsonProperty("post_code")
public String getPostCode() {
return postCode;
}
@JsonProperty("post_code")
public void setPostCode(String postCode) {
this.postCode = postCode;
}
@JsonProperty("location")
public String getLocation() {
return location;
}
@JsonProperty("location")
public void setLocation(String location) {
this.location = location;
}
@JsonProperty("service_store")
public Integer getServiceStore() {
return serviceStore;
}
@JsonProperty("service_store")
public void setServiceStore(Integer serviceStore) {
this.serviceStore = serviceStore;
}
@JsonProperty("service_mechanical_workshop")
public Integer getServiceMechanicalWorkshop() {
return serviceMechanicalWorkshop;
}
@JsonProperty("service_mechanical_workshop")
public void setServiceMechanicalWorkshop(Integer serviceMechanicalWorkshop) {
this.serviceMechanicalWorkshop = serviceMechanicalWorkshop;
}
@JsonProperty("service_restaurant")
public Integer getServiceRestaurant() {
return serviceRestaurant;
}
@JsonProperty("service_restaurant")
public void setServiceRestaurant(Integer serviceRestaurant) {
this.serviceRestaurant = serviceRestaurant;
}
@JsonProperty("service_wash")
public Integer getServiceWash() {
return serviceWash;
}
@JsonProperty("service_wash")
public void setServiceWash(Integer serviceWash) {
this.serviceWash = serviceWash;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
Ответ 2
Вам нужно использовать jackson-kotlin-module
для десериализации в классы данных. Смотрите здесь для деталей.
Сообщение об ошибке выше, что Джексон дает вам, если вы пытаетесь десериализации какого - то значения в класс данных, когда этот модуль не активен или, даже если она есть, когда 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
для десериализации.
Ответ 3
Я попал сюда в поисках этой ошибки:
No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator
Ничего общего с Retrofit, но если вы используете Джексона, эту ошибку можно решить, добавив конструктор по умолчанию в класс, выдавший ошибку.
Больше здесь: https://www.baeldung.com/jackson-exception
Ответ 4
Я знаю, что это старый пост, но для тех, кто использует Retrofit, это может быть полезно.
Если вы используете классы Retrofit + Jackson + Kotlin + Data, вам необходимо:
- добавьте
implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2'
в ваши зависимости, чтобы Джексон мог десериализоваться в классы данных. - При сборке модификации передайте Kotlin Jackson Mapper, чтобы Retrofit использовал правильный маппер, например:
val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()
val retrofit = Retrofit.Builder()
...
.addConverterFactory(JacksonConverterFactory.create(jsonMapper))
.build()
Примечание. Если Retrofit не используется, у @Jayson Minard есть более общий подход.
Ответ 5
У меня были те же симптомы на днях при использовании JsonCreator и JsonProperty, но я получил точно такое же сообщение об ошибке. В моем случае оказалось, что json имеет примитивный тип boolean
, тогда как мой конструктор ожидал класс-обертку Boolean
. Поэтому фреймворк не смог найти подходящего конструктора.
Ответ 6
Если вы используете 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()