android-studio - Gson().fromJson 出错 - “无法在没有参数的情况下调用公共 com.keikakupet.PetStatus()”
问题描述
我正在尝试使用 Gson 库将我的 Kotlin 类的实例存储到 JSON 文件中。但是,当我运行 Gson().fromJson 时,我收到以下错误:
java.lang.RuntimeException:无法调用没有参数的公共 com.keikakupet.PetStatus()
我对错误的理解是 Gson 要求我的类有一个不带参数的主构造函数,因此它可以构造所需的对象(在本例中为 PetStatus 对象)。但是,我有这样一个构造函数。我不确定部分问题是否在于我正在从 init 运行该方法。有谁知道我可以如何解决这个错误?
我的代码:
package com.keikakupet
import android.content.Context
import android.util.Log
import com.google.gson.Gson
import java.io.File
import java.util.*
import java.io.BufferedReader
class PetStatus constructor(){
var maxHealth: Int = 10
var currentHealth: Int = 10
var healthIncrementer: Int = 2 // amount by which health increments when a task is completed
var healthDecrementer: Int = 0 // amount by which health decrements when user approaches / misses deadline
var isHungry: Boolean = false
var isTired: Boolean = false
var isSick: Boolean = false
var isAlive: Boolean = true
init{
//if a json exists, use it to update PetStatus
val context = getContext()
var file = File(context.getFilesDir(), "PetStatus.json")
if(file.exists()){
Log.d("FILE_EXISTS", "File exists!")
val bufferedReader: BufferedReader = file.bufferedReader()
val json = bufferedReader.readText()
val retrievedStatus = Gson().fromJson(json, PetStatus::class.java)
Log.d("JSON_RETRIEVED", json)
}
else
Log.d("FILE_DNE", "File does not exist!")
updateJson()
}
// method to update pet's health and ailment upon completing a task
fun processCompletedTask(){
incrementHealth()
removeAilment()
Log.d("TASK_COMPLETE", "completed task processed")
}
fun getHealthPercent(): Int {
return currentHealth / maxHealth
}
// method to update pet's health and ailment upon missing a task
fun processMissedTask(){
decrementHealth()
addAilment()
Log.d("TASK_MISSED", "missed task processed")
}
/*
Potentially creating another method to update pet's
health and status because of an approaching deadline.
*/
// method to decrement the pet's health
private fun decrementHealth(){
currentHealth-=healthDecrementer
if(currentHealth <= 0)
isAlive = false
updateJson()
}
// method to increment the pet's health
private fun incrementHealth(){
val sum = currentHealth + healthIncrementer
if(sum > maxHealth)
currentHealth = maxHealth
else
currentHealth = sum
updateJson()
}
// method to add an ailment to the pet
private fun addAilment(){
// if no ailment, randomly assign hungry or tired
if(!isHungry && !isTired && !isSick){
val rand = Random()
val randBool = rand.nextBoolean()
if(randBool)
isHungry = true
else
isTired = true
healthDecrementer = 1
}
// otherwise, if hungry XOR tired, assign the other
else if(isHungry && !isTired){
isTired = true
healthDecrementer = 2
}
else if(isTired && !isHungry){
isHungry = true
healthDecrementer = 2
}
// otherwise, if both hungry AND tired, assign sick
else if(isHungry && isTired){
isSick = true
healthDecrementer = 3
}
updateJson()
}
// method to remove an ailment from the pet
private fun removeAilment(){
// if sick, remove sick
if(isSick){
isSick = false
healthDecrementer = 2
}
// otherwise, if hungry and tired, remove one of the two randomly
else if(isHungry && isTired){
val rand = Random()
val randBool = rand.nextBoolean()
if(randBool)
isHungry = false
else
isTired = false
healthDecrementer = 1
}
// otherwise, if hungry XOR tired, remove relevant ailment
else if(isHungry && !isTired){
isHungry = false
healthDecrementer = 0
}
else if(isTired){
isTired = false
healthDecrementer = 0
}
updateJson()
}
private fun updateJson(){
val gson = Gson()
var json: String = gson.toJson(this)
Log.d("JSON_UPDATE", json)
val context = getContext()
var file = File(context.getFilesDir(), "PetStatus.json")
file.writeText(json)
val bufferedReader: BufferedReader = file.bufferedReader()
json = bufferedReader.readText()
Log.d("JSON_FROM_FILE", json)
}
companion object {
private lateinit var context: Context
fun setContext(con: Context) {
context=con
}
fun getContext() : Context {
return context
}
}
}
日志信息:
Caused by: java.lang.RuntimeException: Failed to invoke public com.keikakupet.PetStatus() with no args
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:118)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
at com.google.gson.Gson.fromJson(Gson.java:927)
at com.google.gson.Gson.fromJson(Gson.java:892)
at com.google.gson.Gson.fromJson(Gson.java:841)
at com.google.gson.Gson.fromJson(Gson.java:813)
at com.keikakupet.PetStatus.<init>(PetStatus.kt:32)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:110)
... 4981 more
解决方案
由于您的构造函数没有参数,因此 Gson 无法在 json 的帮助下实例化您的类。
像这样重组你的类:
class PetStatus private constructor(
var maxHealth: Int = 10,
var currentHealth: Int = 10,
var healthIncrementer: Int = 2, // amount by which health increments when a task is completed
var healthDecrementer: Int = 0, // amount by which health decrements when user approaches / misses deadline
var isHungry: Boolean = false,
var isTired: Boolean = false,
var isSick: Boolean = false,
var isAlive: Boolean = true) {
/**
* This is optional fix, since it is a design guideline
* recommendation, you can retain your original function as well
* fun getHealthPercent(): Int {
* return currentHealth / maxHealth
* }
*/
val healthPercent: Int
get() = currentHealth / maxHealth
...
companion object {
lateinit var context: Context // getters and setters for java are automatically generated
operator fun invoke(): PetStatus {
//if a json exists, use it to update PetStatus
val context = context
var file = File(context.getFilesDir(), "PetStatus.json")
if(file.exists()){
Log.d("FILE_EXISTS", "File exists!")
val bufferedReader: BufferedReader = file.bufferedReader()
val json = bufferedReader.readText()
val retrievedStatus = Gson().fromJson(json, PetStatus::class.java)
Log.d("JSON_RETRIEVED", json)
return retrievedStatus
} else {
Log.d("FILE_DNE", "File does not exist!")
return PetStatus()
}
updateJson()
}
operator fun invoke(maxHealth: Int, currentHealth: Int, healthIncrementer: Int, healthDecrementer: Int, isHungry: Boolean, isTired: Boolean, isSick: Boolean, isAlive: Boolean): PetStatus
= PetStatus(maxHealth, currentHealth, healthIncrementer, healthDecrementer, isHungry, isTired, isSick, isAlive)
}
}
现在你可以调用这个类
PetStatus()
operator fun invoke()
是一种 hack (ish) 方法,我建议您实际上应该取出代码并从外部实例化该类。
推荐阅读
- c# - 循环查询匹配并删除子集项
- excel - 满足特定条件的单元格字符串的总和
- angular - 从api接收不同数据类型时如何抛出错误
- ruby - 获取当前 1 年 from_now 作为数字
- javascript - JavaScript 试图读取对象在控制台上给我 undefined
- c# - 如何在 XML 而不是 JSON 中显示 SwaggerResponse
- python - pd.concat() 未在同一索引上合并
- objective-c - Xcode - 如何通过命令行更改文件的目标成员资格?
- javascript - 自引用对象分配中的键
- reactjs - React-Boostrap 模态未显示