web-dev-qa-db-ja.com

デフォルトの構成のような作成者は存在しません):オブジェクト値からデシリアライズできません(デリゲートベースまたはプロパティベースの作成者はありません)

私は逆シリアル化にレトロフィットとジャクソンを使用してAPIを消費しようとしています。 「デフォルトの構成要素などの作成者が存在しない」というタイトルにあるエラー:オブジェクト値からデシリアライズできません(デリゲートベースまたはプロパティベースの作成者なし)が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
        })
}

これは私のviewModelです:

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
)
12
José Nobre

以下のモデルを試してください。 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);
}

}
4
Bek

jackson-kotlin-moduleを使用して、データクラスにデシリアライズする必要があります。詳細については、 here を参照してください。

上記のエラーメッセージは、モジュールが有効になっていない場合、または使用しているObjectMapperKotlinModuleが登録されていない場合でも、何らかの値をデータクラスにデシリアライズしようとした場合にJacksonが提供するものです。たとえば、次のコードをご覧ください。

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)

上記のコードを変更し、ObjectMapperjacksonObjectMapperに置き換えると(登録されたObjectMapperを持つ通常のKotlinModuleを返すだけです)、動作します。つまり.

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

物事のAndroid側についてはわかりませんが、システムがjacksonObjectMapperを使用して逆シリアル化を行う必要があるようです。

14
Yoni Gibbs

私はこのエラーを探してここに来ました:

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

Retrofitとは関係ありませんが、ジャクソンを使用している場合、エラーをスローするクラスにデフォルトコンストラクターを追加することで、このエラーは解決されました。詳細: https://www.baeldung.com/jackson-exception

7
Fede Mika

私はこれが古い投稿であることを知っていますが、Retrofitを使用している人にとっては、これは便利で便利です。

Retrofit + Jackson + Kotlin + Dataクラスを使用している場合、以下が必要です。

  1. jacksonがデータクラスにデシリアライズできるように、implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2'を依存関係に追加します
  2. レトロフィットを構築する場合、Kotlin Jackson Mapperを渡すと、レトロフィットは正しいマッパーを使用します。例:
    val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()

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

注:Retrofitが使用されていない場合、@ Jayson Minardにはより一般的なアプローチの答えがあります。

4
HAT

先日、JsonCreatorとJsonPropertyを使用しているときに同じ症状がありましたが、まったく同じエラーメッセージが表示されました。私の場合、jsonのプリミティブ型はbooleanでしたが、コンストラクターはラッパークラスBooleanを待っていました。そのため、フレームワークは適切なコンストラクターを見つけることができませんでした。

Httpライブラリとして nirest を使用している場合、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()
0
Clement