XMLMapper反序列化AIML混写内容报Expected END_ELEMENT错误如何解决?
问题原因
你遇到的报错本质是Jackson XML模块默认不支持XML混合内容(同一标签内同时存在文本节点和子元素节点)的解析场景。你当前使用的@JacksonXmlText注解仅能捕获标签下的纯文本内容,一旦标签内同时出现子标签,解析器预期读取结束标签时实际读取到子标签的开始标签,就会抛出Expected END_ELEMENT, got event of type 1错误。
解决方案
方案1:使用@JacksonXmlMixed注解适配混合内容(推荐)
这个注解是Jackson XML专门为混合内容场景提供的能力,只需修改Srai类的定义即可:
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlMixed; import java.util.ArrayList; import java.util.List; @JacksonXmlRootElement(localName = "srai") public class Srai { // 用混合内容注解接收所有节点,包括文本节点和子元素节点 @JacksonXmlMixed @JacksonXmlElementWrapper(useWrapping = false) private List<Object> content = new ArrayList<>(); public Srai() {} // 原有getText方法改成遍历content提取所有字符串 public String getText() { StringBuilder sb = new StringBuilder(); for (Object o : content) { if (o instanceof String) { sb.append((String) o); } } return sb.toString().trim(); } // 原有getStars方法改成遍历content提取所有Star对象 public List<Star> getStars() { List<Star> stars = new ArrayList<>(); for (Object o : content) { if (o instanceof Star) { stars.add((Star) o); } } return stars; } public List<Object> getContent() { return content; } public void setContent(List<Object> content) { this.content = content; } }
该方案优势是无需修改上层调用逻辑,原有调用getText()和getStars()的代码可以完全复用,适配所有srai标签的内容场景。
方案2:自定义Srai反序列化器
如果不想改动现有Srai类的字段结构,可以自定义反序列化逻辑手动解析节点:
- 编写自定义反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; import java.util.ArrayList; public class SraiDeserializer extends StdDeserializer<Srai> { public SraiDeserializer() { super(Srai.class); } @Override public Srai deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { Srai srai = new Srai(); List<Star> stars = new ArrayList<>(); StringBuilder text = new StringBuilder(); while (p.nextToken() != JsonToken.END_OBJECT) { if (p.currentToken() == JsonToken.VALUE_STRING) { text.append(p.getText()); } else if (p.currentToken() == JsonToken.START_OBJECT && "star".equals(p.currentName())) { stars.add(p.readValueAs(Star.class)); } } srai.setText(text.toString().trim()); srai.setStars(stars); return srai; } }
- 给Srai类绑定反序列化器
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JacksonXmlRootElement(localName = "srai") @JsonDeserialize(using = SraiDeserializer.class) public class Srai { // 原有字段、getter、setter完全保留不需要改动 }
该方案优势是完全保留原有实体类结构,适合不能改动字段定义的场景。
内容的提问来源于stack exchange,提问作者PabloG
相关产品推荐
相关产品推荐

