android-studio - Gson()。fromJson错误- “Failed to invoke public com.keikakupet.PetStatus() with no args”

标签 android-studio kotlin gson

我正在尝试使用Gson库将Kotlin类的实例存储到JSON文件中。但是,当我运行Gson()。fromJson时,出现以下错误:

java.lang.RuntimeException: Failed to invoke public com.keikakupet.PetStatus() with no args



我对错误的理解是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
        }
    }
}


Logcat信息:

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):

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)
    }
}

现在您可以将类(class)命名为相同

PetStatus()
operator fun invoke()是一种破解方法,我建议您实际上应该将代码取出并从外部实例化该类。

关于android-studio - Gson()。fromJson错误- “Failed to invoke public com.keikakupet.PetStatus() with no args”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61181225/

相关文章:

java - 在选定执行时跳过父类中的 gson 字段

java - Android Studio 预览与设备不同

android-studio - 在 Android Studio 中将 Roboto 设置为我的应用程序的全局字体

android - 如何使用 Firebase 仅使用电话号码和 otp 实现现有用户登录

android - Kotlin 等价于 Java 的 equalsIgnoreCase

android - 使用 Kotlin 数据类的 Json 解析器正确返回 json 数据,但是为什么解析器(MockK)的单元测试会失败?

android - Fresh kotlin android项目配置错误

java - 在java中将JSON字符串转换为不同的java对象

android - NoSuchMethodError Lcom/google/gson/Gson;根据改造响应

android-studio - 如何将-http-proxy添加到从Android Studio 2.0启动的android模拟器中