我正在尝试使用经过改型和杰克逊反序列化的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)
这是我的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
)
答案 0 :(得分:7)
您需要使用jackson-kotlin-module
来反序列化数据类。有关详细信息,请参见here。
如果您尝试在未启用该模块的情况下将某个值反序列化为数据类,或者即使该模块不使用ObjectMapper
时,Jackson也会提供上述错误消息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
进行反序列化。
答案 1 :(得分:5)
由于提到的错误,该类没有默认的构造函数。
将https://github.com/allinurl/goaccess/issues/1133添加到实体类应该对其进行修复。
答案 2 :(得分:4)
我通过添加一个无参数的承包商来解决了这个问题。如果您使用的是 Lombok ,则只需添加key
批注:
@NoArgsConstructor
答案 3 :(得分:4)
我有一个类似的问题(使用Jackson,lombok,gradle)和一个没有args构造函数的POJO-解决方案是添加
lombok.anyConstructor.addConstructorProperties=true
到 lombok.config 文件
答案 4 :(得分:3)
尝试以下型号。我用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);
}
}
答案 5 :(得分:2)
扩展Yoni Gibbs的答案,如果您在使用改造的Android项目中并配置了Jackson的序列化,则可以执行这些操作,以使反序列化可以像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?
答案 6 :(得分:2)
只需要添加 @NoArgsConstructor
就可以了。
答案 7 :(得分:1)
如果使用的是LOMBOK。 如果没有,请创建一个文件lombok.config并添加此行。
if os.getenv('GAE_APPLICATION', None):
# Running on production App Engine, so connect to Google Cloud SQL using
# the unix socket at /cloudsql/<your-cloudsql-connection string>
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '/cloudsql/[YOUR-CONNECTION-NAME]',
'USER': '[YOUR-USERNAME]',
'PASSWORD': '[YOUR-PASSWORD]',
'NAME': '[YOUR-DATABASE]',
}
}
else:
# Running locally so connect to either a local MySQL instance or connect to
# Cloud SQL via the proxy. To start the proxy via command line:
#
# $ cloud_sql_proxy -instances=[INSTANCE_CONNECTION_NAME]=tcp:3306
#
# See https://cloud.google.com/sql/docs/mysql-connect-proxy
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'PORT': '3306',
'NAME': '[YOUR-DATABASE]',
'USER': '[YOUR-USERNAME]',
'PASSWORD': '[YOUR-PASSWORD]',
}
}
答案 8 :(得分:1)
我在这里搜索此错误:
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
答案 9 :(得分:0)
如果您在pojo /模型上使用lombok,请确保您具有这些注释
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
它可能会有所不同,但请确保getter,setter尤其是No Arg构造函数
答案 10 :(得分:0)
使用Lombok Builder时,会出现上述错误。
@JsonDeserialize(builder = StationResponse.StationResponseBuilder.class)
public class StationResponse{
//define required properties
}
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPOJOBuilder(withPrefix = "")
public static class StationResponseBuilder {}
答案 11 :(得分:0)
我将rescu与Kotlin一起使用,并通过使用@ConstructorProperties解决了该问题
data class MyResponse @ConstructorProperties("message", "count") constructor(
val message: String,
val count: Int
)
Jackson使用@ConstructorProperties。这也应该修复Lombok @Data。
答案 12 :(得分:0)
我可以借助@JacksonProperty
注释在Kotlin中解决此问题。上述情况的用法示例为:
import com.fasterxml.jackson.annotation.JsonProperty
...
data class Station(
@JacksonProperty("repsol_id") val repsol_id: String,
@JacksonProperty("name") val name: String,
...
答案 13 :(得分: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()
答案 14 :(得分:0)
前几天,在使用JsonCreator和JsonProperty时,我有相同的症状,但是得到了完全相同的错误消息。就我而言,事实证明json具有原始类型boolean
,而我的构造函数正在等待包装器类Boolean
。因此,该框架无法找到合适的构造函数。
答案 15 :(得分:0)
只需指出,此answer提供了更好的解释。
基本上您可以同时拥有@Getter
和@NoArgConstructor
或者让Lombok使用@ConstructorProperties
文件重新生成lombok.config
,
或使用-parameters
标志编译Java项目,
或者让杰克逊使用龙目岛的@Builder
答案 16 :(得分:0)
我遇到了这个问题,并使用下面的代码修复了该问题。
@Configuration
open class JacksonMapper {
@Bean
open fun mapper(): ObjectMapper {
val mapper = ObjectMapper()
...
mapper.registerModule(KotlinModule())
return mapper
}
}
答案 17 :(得分:0)
我的问题原因在我看来非常罕见,不确定在相同条件下是否还有其他人得到错误,我通过比较以前的提交找到了原因,在这里:
通过我的build.gradle我正在使用这两个编译器选项,并注释掉此行可解决此问题
//compileJava.options.compilerArgs = ['-Xlint:unchecked','-Xlint:deprecation']
答案 18 :(得分:0)
在下面的用例中遇到同样的错误。
我尝试使用 sprint boot(2.0.0 Snapshot Version) 到达 Rest(Put mapping) 端点,而在相应的 bean 中没有 default 构造函数。
但使用最新的 Spring Boot 版本(2.4.1 版本),同一段代码可以正常工作。
因此在最新版本的 Spring Boot 中不再需要 bean 默认构造函数
答案 19 :(得分:0)
我遇到了同样的错误,问题是我的模型没有实现Serializable,所以也检查一下,可能会有所帮助因为这也是原因之一。
答案 20 :(得分:0)
在类中添加构造函数 要么 如果您使用的是 pojo 添加 @NoArgsConstructor @AllArgsConstructor
还包括 JsonProperty -
@JsonProperty("name") private List<Employee> name;
答案 21 :(得分:0)
贝克的回答是正确的。
但是如果有人试图在 restcontroller 中使用不可变类,即他们使用 lombok 的 CREATE TABLE cart_items (
cart_id INT,
prod_id INT,
quantity INT,
UNIQUE KEY (cart_id, prod_id),
FOREIGN KEY (cart_id) REFERENCES cart (cart_id),
FOREIGN KEY (prod_id) REFERENCES product (prod_id)
);
那么你需要添加 @value
您可以在存在根 pom.xml 的同一位置创建一个名为 lombok.anyConstructor.addConstructorProperties=true
的文件,并将此行添加到文件中