You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin+Cojen Maker实现YamlParser遇java.lang.VerifyError错误求助

使用Kotlin+Cojen Maker实现YamlParser时遇到VerifyError问题

我们正在用Kotlin结合Cojen Maker实现YamlParser,现在碰到java.lang.VerifyError: Bad local variable type错误,不清楚错误原因和解决办法。我们推测这个错误和buildYamlParser()方法里的类型转换有关,但移除转换后功能无法正常运行。相关代码、测试类及错误栈信息如下:

核心代码

package pt.isel

import org.cojen.maker.ClassMaker
import org.cojen.maker.MethodMaker
import org.cojen.maker.Variable
import java.lang.reflect.Parameter
import kotlin.reflect.KClass

/**
 * 基于Cojen Maker生成解析器的YamlParser
 */
open class YamlParserCojen<T : Any>(
    private val type: KClass<T>,
    private val nrOfInitArgs: Int
) : AbstractYamlParser<T>(type) {

    companion object {
        private val yamlParsers: MutableMap<String, YamlParserCojen<*>> = mutableMapOf()

        private fun parserName(type: KClass<*>, nrOfInitArgs: Int): String {
            return "YamlParser${type.simpleName}$nrOfInitArgs"
        }

        /**
         * 为指定类型创建YamlParser(基于Cojen Maker),不存在则生成并缓存
         */
        fun <T : Any> yamlParser(
            type: KClass<T>,
            nrOfInitArgs: Int = type.constructors.first().parameters.size
        ): AbstractYamlParser<T> {
            return yamlParsers.getOrPut(parserName(type, nrOfInitArgs)) {
                YamlParserCojen(type, nrOfInitArgs)
                    .buildYamlParser()
                    .finish()
                    .getConstructor(KClass::class.java, Integer::class.java)
                    .newInstance(type, nrOfInitArgs) as YamlParserCojen<*>
            } as YamlParserCojen<T>
        }
    }

    /**
     * 为其他类型获取同类型解析器
     */
    override fun <T : Any> yamlParser(type: KClass<T>) = YamlParserCojen.yamlParser(type)

    fun createNewParser(type: Class<T>) = YamlParserCojen.yamlParser(type.kotlin)

    /**
     * 请勿修改YamlParserCojen中的此方法,会被buildYamlParser动态生成的子类覆盖
     */
    override fun newInstance(args: Map<String, Any>): T {
        throw UnsupportedOperationException("此方法会被buildYamlParser()生成的动态子类覆盖!")
    }

    private fun buildYamlParser(): ClassMaker {
        val cm = ClassMaker.begin(parserName(type, nrOfInitArgs)).extend(YamlParserCojen::class.java).public_()
        val init: MethodMaker = cm.addConstructor(KClass::class.java, Integer::class.java).public_()
        init.invokeSuperConstructor(init.param(0), init.param(1))
        val newInstance = cm.addMethod(Any::class.java, "newInstance", Map::class.java)
        val constructor = type.java.constructors.first { it.parameters.size == nrOfInitArgs }
        val params = constructor.parameters.map { getValueForParam(it, newInstance) }.toTypedArray()
        val returnValue = newInstance.new_(type.java, *params)
        newInstance.return_(returnValue)
        return cm
    }

    private fun getValueForParam(param: Parameter, mm: MethodMaker): Variable {
        val mapValue = mm.param(0).invoke("get", param.name).cast(String::class.java)
        return when (param.type) {
            String::class.java -> mapValue
            Int::class.java -> mm.`var`(Integer::class.java).invoke("parseInt", mapValue.cast(String::class.java))
            Long::class.java -> mm.`var`(Long::class.java).invoke("parseLong", mapValue.cast(String::class.java))
            Short::class.java -> mm.`var`(Short::class.java).invoke("parseShort", mapValue.cast(String::class.java))
            Float::class.java -> mm.`var`(Float::class.java).invoke("parseFloat", mapValue.cast(String::class.java))
            Double::class.java -> mm.`var`(Double::class.java).invoke("parseDouble", mapValue.cast(String::class.java))
            Boolean::class.java -> mm.`var`(Boolean::class.java).invoke("parseBoolean", mapValue.cast(String::class.java))
            List::class.java -> getValueForList(param, mm)
            else -> getValueForObject(param, mm)
        }
    }

    private fun getValueForObject(param: Parameter, mm: MethodMaker): Variable {
        val paramClass = param.type
        val mapValue = mm.param(0).invoke("get", param.name).cast(Map::class.java)
        val yamlParser = mm.`var`(YamlParserCojen::class.java)
            .invoke("createNewParser", paramClass)
        return yamlParser.invoke("newInstance", mapValue).cast(paramClass)
    }


    private fun getValueForList(param: Parameter, mm: MethodMaker): Variable {
        TODO()
    }
}

Student实体类

package pt.isel.test

class Student @JvmOverloads constructor (
    val name: String,
    val nr: Int,
    val from: String,
    val address: Address? = null,
    val grades: List<Grade> = emptyList()
)

测试代码

@Test
fun parseStudentWithAddress() {
    val yaml = """
            name: Maria Candida
            nr: 873435
            address:
              street: Rua Rosa
              nr: 78
              city: Lisbon
            from: Oleiros"""
    val st = YamlParserCojen.yamlParser(Student::class, 4).parseObject(yaml.reader())
    assertEquals("Maria Candida", st.name)
    assertEquals(873435, st.nr)
    assertEquals("Oleiros", st.from)
    assertEquals("Rua Rosa", st.address?.street)
    assertEquals(78, st.address?.nr)
    assertEquals("Lisbon", st.address?.city)
}

错误栈信息

java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    YamlParserStudent4-7.newInstance(Ljava/util/Map;)Ljava/lang/Object; @65: aload
  Reason:
    Type top (current frame, locals[6]) is not assignable to reference type
  Current Frame:
    bci: @65
    flags: { }
    locals: { 'YamlParserStudent4-7', 'java/util/Map', 'java/lang/String', integer, 'java/lang/String', 'java/util/Map' }
    stack: { }
  Bytecode:
    0000000: 2b12 32b9 0011 0200 c000 134d 2b12 34b9
    0000010: 0011 0200 c000 13b8 0019 3e2b 1236 b900
    0000020: 1102 00c0 0013 3a04 2b12 38b9 0011 0200
    0000030: c000 1357 2b12 38b9 0011 0200 c000 0d3a
    0000040: 0519 0612 23b6 001d 1905 b600 21c0 0023
    0000050: 3a07 bb00 2559 2c1d 1904 1907 b700 28b0
    0000060:                                         

    at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3549)
    at java.base/java.lang.Class.getConstructor0(Class.java:3754)
    at java.base/java.lang.Class.getConstructor(Class.java:2442)
    at pt.isel.YamlParserCojen$Companion.yamlParser(YamlParserCojen.kt:36)
    at pt.isel.YamlParserCojenTest.parseStudentWithAddress(YamlParserCojenTest.kt:32)
    ...

内容的提问来源于stack exchange,提问作者João Cardoso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 18:19:49