refactor(codec): map SIS XML through annotated DTOs

This commit is contained in:
windyboy
2026-09-09 19:48:45 +08:00
parent c2d4a76e3e
commit 3ed54d306e
7 changed files with 290 additions and 157 deletions
@@ -3,24 +3,18 @@ package com.gzzn.omms.msgexchange.codec
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText
import com.gzzn.omms.msgexchange.domain.flight.ScheduleRecord
import java.time.LocalDate
/**
* FLOP 报文解析体(单航班增量 §6.1)。
* scalarsFLID 以外的标量;collectionsGTDT/CKDT 等重复集合(含源序号属性)。
*/
/** Stable payload boundary used by processing. It is deliberately not an XML model. */
data class FlopPayload(
val flid: String,
val scalars: Map<String, String> = emptyMap(),
val collections: Map<String, List<Map<String, String>>> = emptyMap(),
)
/**
* SCHDDNLD/RESP/ADFT)解析体(docs/flight-state.md §5)。
* RECS 声明数与实收 FLTR 记录分离承载,完整性校验(§5.2)在处理层执行;
* 协议无报文级覆盖日字段——scope 由处理层按记录 SODT 推导。
*/
data class ScheduleBody(
val recsDeclared: Int,
val records: List<ScheduleRecord>,
@@ -28,46 +22,184 @@ data class ScheduleBody(
val scopeEnd: LocalDate? = null,
)
// =====================================================================
// XML 直接映射(jackson-dataformat-xml 数据绑定,不再手写 DOM 遍历)。
// 信封强类型(META/段结构),FLTR/航班段内标签为开放集 → Map<String, Any>
// 泛型承载(45+ 标签逐一建模不成比例);集合项 = 属性 + 子元素展平的 Map。
// 已知弱项:DELY 的混合文本(元素文本)在 XmlMapper 绑定下不保证保留,
// 属性 CODE/STRT/DURA 保留;备注文本待真实报文验收(§10)。
// =====================================================================
/**
* Wire DTOs for SIS in docs/legacy/SIS_AODB_RMS-V0.1.md.
* SIS permits a subsystem to ignore standard fields it does not use; those fields are
* therefore ignored here, while fields used by the state model are explicitly annotated.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
data class SisMessage(
@JacksonXmlProperty(localName = "META")
val meta: SisMeta? = null,
@JacksonXmlProperty(localName = "SCHD")
val schd: SchdSection? = null,
@JacksonXmlProperty(localName = "FLOP")
val flop: Map<String, Any>? = null,
@JacksonXmlProperty(localName = "FDEL")
val fdel: Map<String, Any>? = null,
@JacksonXmlRootElement(localName = "MSG")
data class SisMessageXml(
@JacksonXmlProperty(localName = "META") val meta: SisMetaXml? = null,
@JacksonXmlProperty(localName = "SCHD") val schd: SchdXml? = null,
@JacksonXmlProperty(localName = "FLOP") val flop: FlightRecordXml? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class SisMeta(
@JacksonXmlProperty(localName = "SNDR")
val sndr: String? = null,
@JacksonXmlProperty(localName = "SEQN")
val seqn: Long? = null,
@JacksonXmlProperty(localName = "DTTM")
val dttm: Long? = null,
@JacksonXmlProperty(localName = "TYPE")
val type: String? = null,
@JacksonXmlProperty(localName = "STYP")
val styp: String? = null,
data class SisMetaXml(
@JacksonXmlProperty(localName = "SNDR") val sndr: String? = null,
@JacksonXmlProperty(localName = "SEQN") val seqn: Long? = null,
@JacksonXmlProperty(localName = "DTTM") val dttm: Long? = null,
@JacksonXmlProperty(localName = "TYPE") val type: String? = null,
@JacksonXmlProperty(localName = "STYP") val styp: String? = null,
)
/** SCHD 段:RECS 声明数 + FLTR 记录集(SIS §3.16 样例结构)。 */
@JsonIgnoreProperties(ignoreUnknown = true)
data class SchdSection(
@JacksonXmlProperty(localName = "RECS")
val recs: Int? = null,
data class SchdXml(
@JacksonXmlProperty(localName = "RECS") val recs: Int? = null,
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "FLTR")
val fltr: List<Map<String, Any>> = emptyList(),
@JacksonXmlProperty(localName = "FLTR") val fltr: List<FlightRecordXml> = emptyList(),
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class FlightRecordXml(
@JacksonXmlProperty(localName = "FLID") val flid: String? = null,
@JacksonXmlProperty(localName = "FFID") val ffid: String? = null,
@JacksonXmlProperty(localName = "FDEL") val fdel: FdelXml? = null,
@JacksonXmlProperty(localName = "SEQN") val seqn: Long? = null,
@JacksonXmlProperty(localName = "ALCD") val alcd: String? = null,
@JacksonXmlProperty(localName = "ALSC") val alsc: String? = null,
@JacksonXmlProperty(localName = "FLNO") val flno: String? = null,
@JacksonXmlProperty(localName = "MVIN") val mvin: String? = null,
@JacksonXmlProperty(localName = "SODT") val sodt: String? = null,
@JacksonXmlProperty(localName = "FLTY") val flty: String? = null,
@JacksonXmlProperty(localName = "FLIN") val flin: String? = null,
@JacksonXmlProperty(localName = "ACFT") val acft: String? = null,
@JacksonXmlProperty(localName = "RENO") val reno: String? = null,
@JacksonXmlProperty(localName = "TAOP") val taop: String? = null,
@JacksonXmlProperty(localName = "TAFL") val tafl: String? = null,
@JacksonXmlProperty(localName = "TAID") val taid: String? = null,
@JacksonXmlProperty(localName = "TRML") val trml: String? = null,
@JacksonXmlProperty(localName = "MAXP") val maxp: String? = null,
@JacksonXmlProperty(localName = "CSOP") val csop: String? = null,
@JacksonXmlProperty(localName = "CSFT") val csft: String? = null,
@JacksonXmlProperty(localName = "MAID") val maid: String? = null,
@JacksonXmlProperty(localName = "ESTT") val estt: String? = null,
@JacksonXmlProperty(localName = "ACTT") val actt: String? = null,
@JacksonXmlProperty(localName = "STND") val stnd: String? = null,
@JacksonXmlProperty(localName = "PHAG") val phag: String? = null,
@JacksonXmlProperty(localName = "CNCL") val cncl: String? = null,
@JacksonXmlProperty(localName = "REMC") val remc: String? = null,
@JacksonXmlProperty(localName = "BOTM") val botm: String? = null,
@JacksonXmlProperty(localName = "LACL") val lacl: String? = null,
@JacksonXmlProperty(localName = "FINT") val fint: String? = null,
@JacksonXmlProperty(localName = "APPT") val appt: String? = null,
@JacksonXmlProperty(localName = "EGSR") val egsr: String? = null,
@JacksonXmlProperty(localName = "EGST") val egst: String? = null,
@JacksonXmlProperty(localName = "FHAG") val fhag: String? = null,
@JacksonXmlProperty(localName = "MHAG") val mhag: String? = null,
@JacksonXmlProperty(localName = "VIPP") val vipp: String? = null,
@JacksonXmlProperty(localName = "VIPR") val vipr: String? = null,
@JacksonXmlProperty(localName = "LBNO") val lbno: String? = null,
@JacksonXmlProperty(localName = "LBWT") val lbwt: String? = null,
@JacksonXmlProperty(localName = "PAXC") val paxc: String? = null,
@JacksonXmlProperty(localName = "EXSC") val exsc: String? = null,
@JacksonXmlProperty(localName = "EXSR") val exsr: String? = null,
@JacksonXmlProperty(localName = "FTSS") val ftss: String? = null,
@JacksonXmlProperty(localName = "PEDT") val pedt: String? = null,
@JacksonXmlProperty(localName = "NAAT") val naat: String? = null,
@JacksonXmlProperty(localName = "NEAT") val neat: String? = null,
@JacksonXmlProperty(localName = "PADT") val padt: String? = null,
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "GTDT") val gtdt: List<GtdtXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "CKDT") val ckdt: List<CkdtXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "CLDT") val cldt: List<CldtXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "PSDT") val psdt: List<PsdtXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "CHDT") val chdt: List<ChdtXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "DELY") val dely: List<DelyXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "ABTM") val abtm: List<AbtmXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "CHOT") val chot: List<ChotXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "ROUT") val rout: List<RoutXml> = emptyList(),
@JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "ERUT") val erut: List<RoutXml> = emptyList(),
)
@JsonIgnoreProperties(ignoreUnknown = true)
class FdelXml
@JsonIgnoreProperties(ignoreUnknown = true)
data class GtdtXml(
@JacksonXmlProperty(isAttribute = true, localName = "GTNO") val gtno: String? = null,
@JacksonXmlProperty(localName = "GATE") val gate: String? = null,
@JacksonXmlProperty(localName = "PGOT") val pgot: String? = null,
@JacksonXmlProperty(localName = "PGCT") val pgct: String? = null,
@JacksonXmlProperty(localName = "GOTM") val gotm: String? = null,
@JacksonXmlProperty(localName = "GCTM") val gctm: String? = null,
@JacksonXmlProperty(localName = "GTYP") val gtyp: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class CkdtXml(
@JacksonXmlProperty(isAttribute = true, localName = "CKNO") val ckno: String? = null,
@JacksonXmlProperty(localName = "CHKC") val chkc: String? = null,
@JacksonXmlProperty(localName = "CCLS") val ccls: String? = null,
@JacksonXmlProperty(localName = "PCOT") val pcot: String? = null,
@JacksonXmlProperty(localName = "PCCT") val pcct: String? = null,
@JacksonXmlProperty(localName = "COTM") val cotm: String? = null,
@JacksonXmlProperty(localName = "CCTM") val cctm: String? = null,
@JacksonXmlProperty(localName = "CTYP") val ctyp: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class CldtXml(
@JacksonXmlProperty(isAttribute = true, localName = "CLNO") val clno: String? = null,
@JacksonXmlProperty(localName = "BELT") val belt: String? = null,
@JacksonXmlProperty(localName = "BCLS") val bcls: String? = null,
@JacksonXmlProperty(localName = "PCOT") val pcot: String? = null,
@JacksonXmlProperty(localName = "PCCT") val pcct: String? = null,
@JacksonXmlProperty(localName = "FBAG") val fbag: String? = null,
@JacksonXmlProperty(localName = "LBAG") val lbag: String? = null,
@JacksonXmlProperty(localName = "BTYP") val btyp: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class PsdtXml(
@JacksonXmlProperty(isAttribute = true, localName = "PSNO") val psno: String? = null,
@JacksonXmlProperty(localName = "PSST") val psst: String? = null,
@JacksonXmlProperty(localName = "STST") val stst: String? = null,
@JacksonXmlProperty(localName = "STET") val stet: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class ChdtXml(
@JacksonXmlProperty(isAttribute = true, localName = "CHNO") val chno: String? = null,
@JacksonXmlProperty(localName = "CHUT") val chut: String? = null,
@JacksonXmlProperty(localName = "CHCLS") val chcls: String? = null,
@JacksonXmlProperty(localName = "PCBT") val pcbt: String? = null,
@JacksonXmlProperty(localName = "PCET") val pcet: String? = null,
@JacksonXmlProperty(localName = "CBTM") val cbtm: String? = null,
@JacksonXmlProperty(localName = "CETM") val cetm: String? = null,
@JacksonXmlProperty(localName = "CHTYP") val chtyp: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class DelyXml(
@JacksonXmlProperty(isAttribute = true, localName = "CODE") val code: String? = null,
@JacksonXmlProperty(isAttribute = true, localName = "STRT") val strt: String? = null,
@JacksonXmlProperty(isAttribute = true, localName = "DURA") val dura: String? = null,
) {
@JacksonXmlText
var text: String? = null
}
@JsonIgnoreProperties(ignoreUnknown = true)
data class AbtmXml(
@JacksonXmlProperty(isAttribute = true, localName = "ASNO") val asno: String? = null,
@JacksonXmlProperty(localName = "ABDG") val abdg: String? = null,
@JacksonXmlProperty(localName = "ABOP") val abop: String? = null,
@JacksonXmlProperty(localName = "AOTM") val aotm: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class ChotXml(
@JacksonXmlProperty(isAttribute = true, localName = "CSNO") val csno: String? = null,
@JacksonXmlProperty(localName = "CHID") val chid: String? = null,
@JacksonXmlProperty(localName = "CHST") val chst: String? = null,
@JacksonXmlProperty(localName = "CHTM") val chtm: String? = null,
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class RoutXml(
@JacksonXmlProperty(isAttribute = true, localName = "RTNO") val rtno: String? = null,
@JacksonXmlProperty(localName = "APCD") val apcd: String? = null,
@JacksonXmlProperty(localName = "SCAT") val scat: String? = null,
@JacksonXmlProperty(localName = "SCDT") val scdt: String? = null,
)