当前位置: 首页 > 知识库问答 >
问题:

Jackson:为地图数据结构注册自定义XML序列化程序

欧阳炜
2023-03-14

Jackson jax-rs内容提供程序用于我们基于jax-rs的REST API项目,以处理json和xml内容类型。作为对POJO的响应,我们有映射结构,我们的要求是将此映射结构序列化为XML中的List和JSON格式的Map。(映射键包含空格,因此不可能将这些键转换为XML元素名称)。为了实现这一点,我们实现了一个自定义的XML序列化程序...

JSON:

"properties":{
    "a b c":{
            "name": "a b c",   
            "value": "xyz"
            }
}

XML:

<property name="a b c" value="xyz"/>

属性地图序列化r:

public class PropertyMapSerializer extends
        JsonSerializer<Map<String, Property>> {

    @Override
    public void serialize(Map<String, Property> value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {

        provider.defaultSerializeValue(value.values(), jgen);
    }
} 

JAX-RS上下文解析器配置为解析配置为使用此序列化器的XMLMapper实例。

@Provider
@Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_XML })
public class XmlMapperContextResolver implements ContextResolver<XmlMapper> {
    private final XmlMapper xmlMapper = new XmlMapper();

    @Override
    public XmlMapper getContext(Class<?> type) {
        return xmlMapper;
    }

    public XmlMapperContextResolver() {
        JacksonXmlModule module = new JacksonXmlModule();
        module.setDefaultUseWrapper(false);

        //Compilation error while adding Serializer for Map and HashMap class. 
        //Error: The method addSerializer(Class<? extends T>, JsonSerializer<T>) in the type SimpleModule is not applicable for the arguments (Class<Map>, PropertyMapSerializer)
        //module.addSerializer(HashMap.class, new PropertyMapSerializer());
        //module.addSerializer(Map.class, new PropertyMapSerializer());

        //This works
        module.addSerializer(PropertyMap.class, new PropertyMapSerializer());

        xmlMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
        xmlMapper.registerModule(module);
    }
}

其中PropertyMap是HashMap的一个子类:

public class PropertyMap extends HashMap<String, Property> {
}

响应POJO:

public class ResponsePOJO {
    //Commenting out as serializer couldn't be added for HashMap
    //private Map<String, Property> properties = new HashMap<String, Property>();
    private Map<String, Property> properties = new PropertyMap();
}

请告诉我,为什么我不能为HashMap添加序列化程序,而为其子类us添加序列化程序?因此,我不得不创建标准数据结构的子类来添加自定义序列化程序。

但同时支持使用Map注释添加自定义序列化程序,并且可以正常工作:

@JsonSerialize(using=PropertyMapSerializer.class)
private Map<String, Property> properties = new HashMap<String, Property>();

以这种方式添加序列化程序将使序列化程序同时适用于json和xml格式。不幸的是,我不能这样做,因为这个序列化程序只适用于XML格式。请分享你的想法。

共有2个答案

晁璞
2023-03-14

你可以试试这样:

@JsonProperty("rowdata")
@JacksonXmlElementWrapper(localName = "ROWDATA")
@JacksonXmlProperty(localName = "ROW")
private List<Row> rows;

Row类是

@JsonSerialize(using = Row.Serializer.class)
public class Row {

    private HashMap<String, String> data;

    public HashMap<String, String> getData() {
        return data;
    }

    public void setData(HashMap<String, String> data) {
        this.data = data;
    }

    public static class Serializer extends StdSerializer<Row> {

        public Serializer() {
            this(null);
        }

        public Serializer(Class<Row> t) {
            super(t);
        }

        @Override
        public void serialize(Row row, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (jsonGenerator instanceof ToXmlGenerator) {
                final ToXmlGenerator xmlGenerator = (ToXmlGenerator) jsonGenerator;
                jsonGenerator.writeStartObject();
                for (Map.Entry<String, String> item : row.getData().entrySet()) {
                    if (item.getValue() == null) {
                        continue;
                    }
                    xmlGenerator.setNextIsAttribute(true);

                    jsonGenerator.writeFieldName(item.getKey());
                    jsonGenerator.writeString(item.getValue());
                }
                jsonGenerator.writeEndObject();
            } else {
                jsonGenerator.writeStartObject();
                for (Map.Entry<String, String> item : row.getData().entrySet()) {
                    if (item.getValue() == null) {
                        continue;
                    }
                    jsonGenerator.writeFieldName(item.getKey());
                    jsonGenerator.writeString(item.getValue());
                }
                jsonGenerator.writeEndObject();
            }
        }
    }
}

它适用于JSON和XML。我的主要目标是将行数据表示为行元素的XML属性。我还希望JSON具有相同的数据结构。下面是它的响应:XML

<ROWDATA>
    <ROW F20="0" F14="1" F13="FUBAR"/>
    <ROW F20="1" F14="0" F13="FIDO"/>
</ROWDATA>

JSON

"rowdata": [
    {
        "F20": "0",
        "F14": "1",
        "F13": "FUBAR"
    },
    {
        "F20": "1",
        "F14": "0",
        "F13": "FIDO"
    }
],
曾弘扬
2023-03-14

我不知道这是否有帮助,但我发现这对我来说很有效。在序列化程序中,我重写handleType()方法,如下所示:

public class MapToTuple extends JsonSerializer<Map<String, Property>> {

     @Override
     public void serialize(final Map<String, Property> map, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonProcessingException {
          /*Serializing code here*/
     }

     @Override
     public Class<Map<String, Property>> handledType() {
         Class<Map<String, Property>> typeClass = (Class<Map<String, Property>>)(Class<?>)Map.class;
         return typeClass;
     }
}

然后我像这样注册序列化程序:

    SimpleModule mapSerializerModule = new SimpleModule("MapSerializerModule", new Version(1, 0, 0, "beta"));
    mapSerializerModule.addSerializer(new MapToTuple());

    mapper.registerModule(mapSerializerModule);

希望这有帮助。

 类似资料:
  • 我目前正在尝试使用Jackson2.8.4将自定义映射类型序列化和反序列化为JSON。我已经设法基于这个答案实现了序列化,但我正在与反序列化作斗争。下面是一个例子:

  • 我有一个类,它通过实现中的和方法来实现自定义Kryo序列化程序(请参见下面的示例)。如何用Spark注册此自定义序列化程序? 现在在Spark: 不幸的是,Spark没有给我注册自定义序列化程序的选项。你知道有没有办法做到这一点?

  • 我试图创建会影响序列化值的自定义jackson注释。 意思是: 现在序列化对象X(10)将导致: 我怎样才能做到这一点?

  • 问题内容: 我正在尝试创建将影响序列化值的自定义杰克逊注释。 含义: 现在序列化对象X(10)将导致: 我该如何实现? 问题答案: 结果:

  • 情况如下:我已经设法让Jackson反序列化以下通用 作为HTTP客户端,并使用exchange

  • 下面的代码再现了这个问题: 上面的代码不做其他注册“自定义”序列化程序的事情(只是委托回原始序列化程序),但它生成的JSON没有null属性: {“第一个”:“鲍勃”,“最后一个”:“巴克”} 我读过许多看似相关的SO文章,但没有一篇能让我找到解决方案。我尝试在序列化时显式地将映射器设置为,但没有成功。 我唯一的线索是JavaDoc for JsonSerializer中的一条注释: 注意:永远不