没有创建者,如默认构造,不存在:无法从对象值反序列化(没有基于委托或基于属性的创建者

Jos*_*bre 18 android jackson kotlin retrofit2

我正在尝试使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的HomeFragment:

onCreate(){
 viewModel.retrieveStation().observe(this, Observer {
            dataBinding.favouriteStationTxt.text = it.name
        })
}
Run Code Online (Sandbox Code Playgroud)

这是我的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)},{})
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的存储库:

class StationRepository @Inject constructor(var apiManager: ApiManager) {

    fun getStationFromId(stationId:Int,onSuccess: (Station)->Unit, onError: (Exception)->Unit){
        apiManager.getStation(stationId, onSuccess,onError)
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的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)
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的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()))
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的STationsApiService(基本URL在口味中)

@GET("{station_id}")
    fun getStation(@Path("station_id") stationId: Int): Call<StationResponse>
Run Code Online (Sandbox Code Playgroud)

这是我的StationResponse

class StationResponse (
        @JsonProperty("data")
        val data: Station)
Run Code Online (Sandbox Code Playgroud)

这是我的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
)
Run Code Online (Sandbox Code Playgroud)

这是我的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
)
Run Code Online (Sandbox Code Playgroud)

Bek*_*Bek 97

原因:发生此错误是因为jackson library不知道如何创建没有的模型,empty constructor并且模型包含的构造函数的参数未使用@JsonProperty("field_name"). 默认情况下,如果您没有向类添加构造函数,java 编译器会创建空的构造函数。

解决方案: 添加empty constructor到您的模型或注释构造函数参数@JsonProperty("field_name")

如果你使用kotlin data classthen 也可以注释@JsonProperty("field_name")或注册jackson 模块 kotlinObjectMapper.

您可以使用http://www.jsonschema2pojo.org/创建模型。

  • 这样做的原因是因为它们不是数据类。 (8认同)
  • @Maximus我认为性能没有区别(如果你的意思是性能更好)。创建空构造函数比在每个参数上添加注释更容易。 (3认同)
  • 这就是解决方案。但哪种方式更好呢?一般创建一个空构造函数还是添加 JSON 属性? (2认同)

小智 46

如果您在POJO 模型上使用Lombok,请确保您有以下注释:

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
Run Code Online (Sandbox Code Playgroud)

它可能会有所不同,但请确保@Getter尤其是@NoArgsConstructor

  • `@Data` 相当于 `@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode` 所以可能只需要 `@NoArgsConstructor` (7认同)
  • `@NoArgsConstructor` 解决了我的情况。我的完整注释是“@Data @AllArgsConstructor @NoArgsConstructor @Entity @JsonInclude(Ininclude.NON_DEFAULT)” (4认同)
  • 在我的例子中,“@NoArgsConstructor”和“@AllArgsConstructor”都是需要的。谢谢! (3认同)
  • 只是想指出你拯救了我的日子:),我一直缺少 @NoArgsConstructor 注释。 (2认同)

Yon*_*bbs 20

您需要使用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)
Run Code Online (Sandbox Code Playgroud)

这将失败,并显示以下错误:

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)
Run Code Online (Sandbox Code Playgroud)

如果您更改上面的代码并替换ObjectMapperjacksonObjectMapper(仅返回ObjectMapperKotlinModule注册的普通代码),则它可以工作。即

val deserializedValue = jacksonObjectMapper().readerFor(TestDataClass::class.java).readValue<TestDataClass>(jsonString)
Run Code Online (Sandbox Code Playgroud)

我不确定Android方面的问题,但看起来您需要让系统使用jacksonObjectMapper进行反序列化。

  • 该问题肯定与不使用此模块和使用数据类有关。因此,您需要在系统正在使用的对象映射器上注册模块。在您正在使用的框架中找到可以在其中修改对象映射器的配置以调用`mapper.registerModule(KotlinModule())`@jose的地方 (3认同)
  • José和Jayson撰写有关json的文章:-D (2认同)

Mic*_*lPr 20

我正在使用 Quarkus、Jackson 和 Lombok。所以我通过@Jacksonized在模型类上添加属性来解决这个问题。所以所有属性都是:

@Jacksonized //missing
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ...
Run Code Online (Sandbox Code Playgroud)


Fed*_*ika 12

我在这里搜索此错误:

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

与Retrofit无关,但是如果您使用的是Jackson,则可以通过向引发错误的类中添加默认构造函数来解决此错误。此处更多信息:https : //www.baeldung.com/jackson-exception

  • 如果您希望对象不可变,则不需要创建默认构造函数。在构造函数上添加 `@JsonCreator` 或 `@ConstructorProperties({"prop1Name", "propr2Name"})` 可解决上述错误。 (10认同)
  • 如果您使用 Lobok 和 @Data,请确保您的字段不是最终字段,否则不可能为空构造函数。所以这是行不通的:`@Data static class LoginResponse { private Final String token, message; 私人最终int状态;但这是有效的:`@Data static class LoginResponse { private String token, message; 私有 int 状态;}` (2认同)

小智 11

我正在使用龙目岛。我收到错误是因为我没有放入@NoArgsConstructor模型类。


小智 9

我知道这是一篇旧帖子,但对于任何使用 Retrofit 的人来说,这可能很有用。

如果你使用 Retrofit + Jackson + Kotlin + Data 类,你需要:

  1. 添加implement group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.7.1-2'到您的依赖项中,以便 Jackson 可以反序列化为 Data 类
  2. 在构建改造时,通过 Kotlin Jackson Mapper,以便 Retrofit 使用正确的映射器,例如:
    val jsonMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()

    val retrofit = Retrofit.Builder()
          ...
          .addConverterFactory(JacksonConverterFactory.create(jsonMapper))
          .build()
Run Code Online (Sandbox Code Playgroud)

注意:如果没有使用 Retrofit,@Jayson Minard 有一个更通用的方法答案。


Ole*_*kii 9

如果使用的话lombok可以使用@Jacksonized注释。

您不需要设置器 - 此注释可以很好地与@Value.

你不需要@NoArgsConstructor- 你可以使用@Builder或 只是@RequiredArgsConstructor.

  • 当将“@Jacksonized”与“@Builder”一起使用时,“@Value”是可选的(可能用于其他目的),但对于杰克逊化本身来说不是必需的。 (3认同)

Ous*_*ama 7

我通过添加无参数构造函数解决了这个问题。如果您使用的是Lombok,则只需要添加@NoArgsConstructor注释:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
public class User {
    private Long userId;
    private String shortName;
}
Run Code Online (Sandbox Code Playgroud)


小智 6

我正在 Kotlin 中使用rescu并使用 @ConstructorProperties 解决它

    data class MyResponse @ConstructorProperties("message", "count") constructor(
        val message: String,
        val count: Int
    )
Run Code Online (Sandbox Code Playgroud)

杰克逊使用@ConstructorProperties。这也应该修复 Lombok @Data 。


Dom*_*inc 6

我有一个类似的问题(使用 Jackson、lombok、gradle)和一个没有 args 构造函数的 POJO - 解决方案是添加

lombok.anyConstructor.addConstructorProperties=true
Run Code Online (Sandbox Code Playgroud)

lombok.config文件


Gay*_*tti 6

由于提到的错误,该类没有默认构造函数。

@NoArgsConstructor添加到实体类应该可以修复它。


sad*_*hna 6

只需添加@NoArgsConstructor即可运行。