提问者:小点点

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


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个答案

匿名用户

我不知道这是否有帮助,但我发现这对我来说很有效。在序列化程序中,我重写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);

希望这有帮助。

匿名用户

你可以试试这样:

@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"
    }
],