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

Jackson XML序列化非基本类型为属性报错Trying to write an attribute求解

解决方案

问题根源

Jackson XML序列化时,对于自定义类、集合这类非简单类型,即使标注了isAttribute = true,默认也会按照复杂对象逻辑生成嵌套子元素;如果自定义序列化器错误调用了writeStartObject等生成结构化内容的方法,就会抛出属性写入时无开放起始元素的异常。

具体修改步骤

1. 新增Rectangle类型转换器

和你已有的ListConverter逻辑一致,把Rectangle对象转为符合格式要求的字符串:

public class BoundsConverter extends StdConverter<Rectangle, String> {
    @Override
    public String convert(Rectangle bounds) {
        if (bounds == null) {
            return "";
        }
        int x2 = bounds.x + bounds.width;
        int y2 = bounds.y + bounds.height;
        return String.format("[%d,%d][%d,%d]", bounds.x, bounds.y, x2, y2);
    }
}

2. 修正实体类注解

给两个非简单类型字段的@JsonSerialize注解补充as = String.class,明确告诉Jackson序列化后输出为字符串类型,避免按复杂对象处理:

@JacksonXmlProperty(localName = "tags", isAttribute = true)
@JsonDeserialize(using = ListDeserializer.class)
// 明确序列化后为字符串类型
@JsonSerialize(converter = ListConverter.class, as = String.class)
private List<String> tags;

@JacksonXmlProperty(localName = "bounds", isAttribute = true)
@JsonDeserialize(using = BoundsDeserializer.class)
// 用新增的BoundsConverter做转换,明确输出为字符串
@JsonSerialize(converter = BoundsConverter.class, as = String.class)
private Rectangle bounds;

3. 可选:XmlMapper配置优化

如果使用Jackson 2.13及以上版本,推荐用builder模式初始化XmlMapper,避免旧版本默认配置的兼容问题:

XmlMapper mapper = XmlMapper.builder()
        .enable(SerializationFeature.INDENT_OUTPUT)
        // 禁止空标签自动转为null,避免反序列化异常
        .disable(FromXmlParser.Feature.EMPTY_ELEMENT_AS_NULL)
        .build();

自定义序列化器的正确写法(如果不用Converter的场景)

如果你想改用自定义Serializer而不是Converter,注意不要调用任何生成结构化节点的方法,直接输出字符串即可:

public class BoundsSerializer extends JsonSerializer<Rectangle> {
    @Override
    public void serialize(Rectangle value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
        int x2 = value.x + value.width;
        int y2 = value.y + value.height;
        String boundsStr = String.format("[%d,%d][%d,%d]", value.x, value.y, x2, y2);
        // 直接写字符串,不要调用writeStartObject等方法
        gen.writeString(boundsStr);
    }
}

实体类对应修改为:

@JacksonXmlProperty(localName = "bounds", isAttribute = true)
@JsonDeserialize(using = BoundsDeserializer.class)
@JsonSerialize(using = BoundsSerializer.class)
private Rectangle bounds;

内容的提问来源于stack exchange,提问作者AweSIM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:48:00