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
相关产品推荐
相关产品推荐

