如何序列化地图中对象值的类型属性?

时间:2015-11-02 09:17:18

标签: java serialization jackson

我需要一些帮助。我必须得到下一个json:

{
  "433434" : {
    "type" : "MULTIPLE",
    "value" : [ {
      "type" : "NUMBER",
      "value" : 322332
    }, {
      "type" : "NUMBER",
      "value" : 322332
    } ]
  }
}

但我有这个:

{
  "433434" : {
    "value" : [ {
      "type" : "NUMBER",
      "value" : 322332
    }, {
      "type" : "NUMBER",
      "value" : 322332
    } ]
  }
}

我正在使用杰克逊。它是我的主要班级

package com.un1acker;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.un1acker.characteristic.AbstractCharacteristic;
import com.un1acker.characteristic.MultipleCharacteristic;
import com.un1acker.characteristic.NumCharacteristic;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

        NumCharacteristic numCharacteristic = new NumCharacteristic();
        numCharacteristic.setValue(BigInteger.valueOf(322332L));
        List<AbstractCharacteristic<?>> list = new ArrayList<>();
        list.add(numCharacteristic);
        list.add(numCharacteristic);
        StringWriter sw = new StringWriter();
        MultipleCharacteristic multipleCharacteristic = new MultipleCharacteristic();
        multipleCharacteristic.setValue(list);
        Map<String, AbstractCharacteristic<?>> map = new HashMap<>();
        map.put("433434", multipleCharacteristic);
        mapper.writeValue(sw, map);

        System.out.println(sw.toString());
    }
}

我有从AbstractCharacteristic扩展的类MultipleCharateristic和NumberCharacteristic。计划我们有地图&gt;,其中包含值MultipleCharacteristic。 在NumberCharacteristic值的MultipleCharacteristic集列表中。

package com.un1acker.characteristic;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "type"
)
@JsonSubTypes({     @JsonSubTypes.Type(
        value = NumCharacteristic.class,
        name = "NUMBER"
), @JsonSubTypes.Type(
        value = MultipleCharacteristic.class,
        name = "MULTIPLE")})
public abstract class  AbstractCharacteristic<T>{

    private static final long serialVersionUID = -6524899961842198462L;
    private T value;

    public AbstractCharacteristic() {
    }

    public T getValue() {
        return this.value;
    }

    protected void setValue(T value) {
        this.value = value;
    }
}

NumCharacteristic Class

package com.un1acker.characteristic;

import java.math.BigInteger;

public class NumCharacteristic extends AbstractCharacteristic<BigInteger> {
    private static final long serialVersionUID = 9220460768952701281L;

    public NumCharacteristic() {
    }
    public void setValue(BigInteger value) {
        super.setValue(value);
    }
}

MultipleCharacteristic class

package com.un1acker.characteristic;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.un1acker.MyCustomSerializer;

import java.util.List;
public class MultipleCharacteristic extends AbstractCharacteristic<List<? extends AbstractCharacteristic<?>>> {
    @Override
    public void setValue(List<? extends AbstractCharacteristic<?>> value) {
        super.setValue(value);
    }

    @Override
    @JsonSerialize(using = MyCustomSerializer.class)

    public List<? extends AbstractCharacteristic<?>> getValue() {
        return super.getValue();
    }
}

我尝试使用覆盖方法serializeWithType为MultipleClass创建自定义序列化,但这不起作用。

2 个答案:

答案 0 :(得分:0)

这看起来可能是杰克逊的错误。你的MultipleCharacteristic类型序列化很好并且包含了它自己的类型,但是当它是一个地图值时却不是,我希望它的工作方式相同:

@Test // passes
public void serialize_multiple_characteristic() throws Exception {
    MultipleCharacteristic chr = new MultipleCharacteristic();
    chr.setValue(new ArrayList<>());
    ObjectMapper mapper = new ObjectMapper();
    assertThat(mapper.writeValueAsString(chr), equivalentTo("{ type: 'MULTIPLE', value: [] }"));
}

@Test // fails, got: {"xyzzy":{"value":[]}}
public void serialize_multiple_characteristic_in_map_value() throws Exception {
    MultipleCharacteristic chr = new MultipleCharacteristic();
    chr.setValue(new ArrayList<>());
    ObjectMapper mapper = new ObjectMapper();
    Map<String, MultipleCharacteristic> map = new HashMap<>();
    map.put("xyzzy", chr);
    assertThat(mapper.writeValueAsString(map), equivalentTo("{ 'xyzzy': { type: 'MULTIPLE', value: [] } }"));
}

(透过内部看,BeanSerializer永远不会被TypeWrappedSerializer包裹)

如果地图嵌入某个地方,这个可能可能不是问题,好像杰克逊知道地图的类型参数(例如它通常从包含的bean获取,例如)它似乎做对了:

@Test // passes
public void serialize_multiple_characteristic_in_map_value_using_writer() throws Exception {
    MultipleCharacteristic chr = new MultipleCharacteristic();
    chr.setValue(new ArrayList<>());
    ObjectMapper mapper = new ObjectMapper();
    Map<String, AbstractCharacteristic<?>> map = new HashMap<>();
    map.put("xyzzy", chr);
    // Hint to Jackson what types will be in the map
    TypeReference<?> mapType = new TypeReference<Map<String, AbstractCharacteristic<?>>>(){};
    assertThat(mapper.writerFor(mapType).writeValueAsString(map), equivalentTo("{ 'xyzzy': { type: 'MULTIPLE', value: [] } }"));
}

一种解决方法,如果您只需要生成JSON并且无法更改代码以使用ObjectWrite,则使用ObjectNode而不是Map:

@Test
public void serialize_multiple_characteristic_in_json_node() throws Exception {
    MultipleCharacteristic chr = new MultipleCharacteristic();
    chr.setValue(new ArrayList<>());
    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.getNodeFactory().objectNode();
    node.putPOJO("xyzzy", chr);
    assertThat(mapper.writeValueAsString(node), equivalentTo("{ 'xyzzy': { type: 'MULTIPLE', value: [] } }"));
}

答案 1 :(得分:0)

这对我有用:为MultipleCharacteristic添加自定义序列化程序:

public class MultipleCharacteristicValueSerializer extends JsonSerializer<MultipleCharacteristic> {

    @Override
    public void serialize(MultipleCharacteristic multipleCharacteristicValue, JsonGenerator jsonGenerator,SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        jsonGenerator.writeFieldName("value");
        jsonGenerator.writeStartArray();
        for (AbstractCharacteristic<?> characteristicValue : multipleCharacteristicValue.getValue()) {
            jsonGenerator.writeObject(characteristicValue);
        }
        jsonGenerator.writeEndArray();
    }

    @Override
    public void serializeWithType(MultipleCharacteristic value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException {
        typeSer.writeTypePrefixForObject(value, jgen);
        serialize(value, jgen, provider);
        typeSer.writeTypeSuffixForObject(value, jgen);
    }

    @Override
    public Class<MultipleCharacteristic> handledType() {
        return MultipleCharacteristic.class;
    }
}