fix(codec): 解码映射失败产出 CODEC_ERROR,落实退避重试与可重放白名单
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.gzzn.omms.msgexchange.codec
|
package com.gzzn.omms.msgexchange.codec
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
|
import com.fasterxml.jackson.databind.JsonMappingException
|
||||||
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlFactory
|
import com.fasterxml.jackson.dataformat.xml.XmlFactory
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper
|
import com.fasterxml.jackson.dataformat.xml.XmlMapper
|
||||||
@@ -34,6 +35,14 @@ class JacksonXmlCodec : XmlCodec {
|
|||||||
}
|
}
|
||||||
val msg = try {
|
val msg = try {
|
||||||
mapper.readValue(trimmed, SisMessageXml::class.java)
|
mapper.readValue(trimmed, SisMessageXml::class.java)
|
||||||
|
} catch (e: JsonMappingException) {
|
||||||
|
// META 层绑定失败=发送方违反必填契约(MALFORMED);体层(SCHD/FLOP)结构不匹配
|
||||||
|
// =wire 结构超出编解码器当前绑定能力(CODEC_ERROR:退避重试,修复后可重放,design §2.3)。
|
||||||
|
val first = e.path.firstOrNull()?.fieldName ?: ""
|
||||||
|
if (first.equals("meta", ignoreCase = true)) {
|
||||||
|
return DecodeResult.Err(DecodeFailure(ErrorClass.MALFORMED, "xml-meta:${e.originalMessage.take(200)}"))
|
||||||
|
}
|
||||||
|
return DecodeResult.Err(DecodeFailure(ErrorClass.CODEC_ERROR, "xml-mapping:${e.originalMessage.take(200)}"))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return DecodeResult.Err(
|
return DecodeResult.Err(
|
||||||
DecodeFailure(ErrorClass.MALFORMED, "xml-parse:${e.message?.take(200) ?: e.javaClass.simpleName}"),
|
DecodeFailure(ErrorClass.MALFORMED, "xml-parse:${e.message?.take(200) ?: e.javaClass.simpleName}"),
|
||||||
|
|||||||
@@ -94,6 +94,26 @@ class JacksonXmlCodecTest {
|
|||||||
assertTrue(err.failure.detail.contains("empty-or-non-xml"))
|
assertTrue(err.failure.detail.contains("empty-or-non-xml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `body shape beyond binding capability is CODEC_ERROR while meta violations stay MALFORMED`() {
|
||||||
|
val meta = "<META><SNDR>AODB</SNDR><SEQN>1</SEQN><DTTM>20021010090311</DTTM><TYPE>SCHD</TYPE><STYP>DNLD</STYP></META>"
|
||||||
|
val recsAsText = "<MSG>$meta<SCHD><RECS>not-a-number</RECS></SCHD></MSG>"
|
||||||
|
val bodyErr = codec.decode(recsAsText) as DecodeResult.Err
|
||||||
|
assertEquals(com.gzzn.omms.msgexchange.domain.ErrorClass.CODEC_ERROR, bodyErr.failure.errorClass)
|
||||||
|
assertTrue(bodyErr.failure.detail.startsWith("xml-mapping"))
|
||||||
|
|
||||||
|
val badSeqn = "<MSG><META><SNDR>AODB</SNDR><SEQN>abc</SEQN><DTTM>20021010090311</DTTM><TYPE>SCHD</TYPE><STYP>DNLD</STYP></META></MSG>"
|
||||||
|
val metaErr = codec.decode(badSeqn) as DecodeResult.Err
|
||||||
|
assertEquals(com.gzzn.omms.msgexchange.domain.ErrorClass.MALFORMED, metaErr.failure.errorClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `broken token stream stays MALFORMED`() {
|
||||||
|
val err = codec.decode("<MSG><META>") as DecodeResult.Err
|
||||||
|
assertEquals(com.gzzn.omms.msgexchange.domain.ErrorClass.MALFORMED, err.failure.errorClass)
|
||||||
|
assertTrue(err.failure.detail.startsWith("xml-parse"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SIS documented attributes and mixed DELY text become typed payload`() {
|
fun `SIS documented attributes and mixed DELY text become typed payload`() {
|
||||||
val raw = """
|
val raw = """
|
||||||
|
|||||||
Reference in New Issue
Block a user