Jackson自定义序列化程序,用于某些字段的自定义行为,同时具有其余字段的默认行为

时间:2017-01-09 11:23:19

标签: java json serialization jackson fasterxml

例如,我有一个POJO定义如下,jackson-corejackson-databind(版本2.8.3)注释省略了getter和setter以简洁。

class Sample {
     private String foo;
     private String bar;
     private Map<String, Map<String, Object>> data;
}

我想编写一个自定义序列化程序,它接受POJO并生成

{
     "foo":"val",
     "bar":"val2",
     "data_1": {
          "someInt":1
     },
     "data_2": {
          "someBoolean":true
     }
}

此处data_1data_2是主Map的键,其内部属性由其子地图(嵌套地图)组成。此外,实际的属性数据根本不应出现在结果JSON中。

请注意foo和bar是字段的示例,实际上pojo有15个以上的字段。

3 个答案:

答案 0 :(得分:0)

请更正您的班级变量数据,  它应该是这样的

public static void serializeSample() {
    ObjectMapper mapper = new ObjectMapper();
    Sample sample=new Sample();
    sample.setBar("val2");
    sample.setFoo("val");
    Map<String, Map<String, Object>> sampleData=new HashMap<>();
    Map<String, Object> data_3=new HashMap<>();
    Map<String, Object> data_4=new HashMap<>();
    data_3.put("someInt", 1);
    data_4.put("someBoolean", Boolean.TRUE);

    sampleData.put("data_1", data_3);
    sampleData.put("data_2", data_4);
    sample.setData(sampleData);

    try {
        mapper.writeValue(new File("log.txt"), sample);
    } catch (JsonGenerationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JsonMappingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }



}

然后编写一个序列化方法,如

<html>
<body>

<select type="select" name="optRes3" select id="optRes1">
    <option value="" disabled selected hidden>Please select an option...</option>
  <option value="Art">Art</option>
  <option value="Business Studies">Business Studies</option>
  <option value="Computing">Computing</option>
  <option value="Drama">Drama</option>
  <option value="French">French</option>
  <option value="Food Technology">Food Technology</option>
  <option value="Geography">Geography</option>
  <option value="German">German</option>
  <option value="History">History</option>
  <option value="Music">Music</option>
  <option value="Philosophy and Ethics">Philosophy and Ethics</option>
  <option value="Product Design">Product Design</option>
  <option value="Physical Education">Physical Education</option>
  <option value="Spanish">Spanish</option>
  <option value="Science (Triple)">Science (Triple Award - 3 GCSEs)</option>
  <option value="Textiles">Textiles</option>
</select>
<select type="select" name="optRes3" select id="optRes2">
    <option value="" disabled selected hidden>Please select an option...</option>
  <option value="Art">Art</option>
  <option value="Business Studies">Business Studies</option>
  <option value="Computing">Computing</option>
  <option value="Drama">Drama</option>
  <option value="French">French</option>
  <option value="Food Technology">Food Technology</option>
  <option value="Geography">Geography</option>
  <option value="German">German</option>
  <option value="History">History</option>
  <option value="Music">Music</option>
  <option value="Philosophy and Ethics">Philosophy and Ethics</option>
  <option value="Product Design">Product Design</option>
  <option value="Physical Education">Physical Education</option>
  <option value="Spanish">Spanish</option>
  <option value="Science (Triple)">Science (Triple Award - 3 GCSEs)</option>
  <option value="Textiles">Textiles</option>
</select>
<select type="select" name="optRes3" select id="optRes3">
    <option value="" disabled selected hidden>Please select an option...</option>
  <option value="Art">Art</option>
  <option value="Business Studies">Business Studies</option>
  <option value="Computing">Computing</option>
  <option value="Drama">Drama</option>
  <option value="French">French</option>
  <option value="Food Technology">Food Technology</option>
  <option value="Geography">Geography</option>
  <option value="German">German</option>
  <option value="History">History</option>
  <option value="Music">Music</option>
  <option value="Philosophy and Ethics">Philosophy and Ethics</option>
  <option value="Product Design">Product Design</option>
  <option value="Physical Education">Physical Education</option>
  <option value="Spanish">Spanish</option>
  <option value="Science (Triple)">Science (Triple Award - 3 GCSEs)</option>
  <option value="Textiles">Textiles</option>
</select>

<script>
function OptResDropdown(htmlDropdown, value) {
    this.value = value;
    this.dropdown = htmlDropdown;
    this.options = this.initOptions(htmlDropdown.options);
    var selected = htmlDropdown.options[htmlDropdown.selectedIndex];
    this.value = value? value : (selected ? selected.value : 0); 
    var me = this;
    htmlDropdown.addEventListener('change', function(event){
        me.value = event.target.value;
        me.update(me.value);
    });
    this.update();
}

OptResDropdown.instances = {};

OptResDropdown.prototype.initOptions = function(options){
    var me = this;
    var out = [];
    for(var i = 0; i < options.length; i++) {
        var option = options[i];
        out.push({value: option.value, label: option.innerText});
    }
    return out;
};

OptResDropdown.prototype.update = function(value) {
    for(var key in OptResDropdown.instances) {
        var me = OptResDropdown.instances[key];
        me.dropdown.innerHTML = '';
        var options;
        if(value === 'Art') {
            options = me.options.filter(function(option){
                return option.value !== 'Textiles';
            });
        } else if(value === 'Textiles') {
            options = me.options.filter(function(option){
                return option.value !== 'Art';
            });
        } else {
            options = me.options;
        }
        options.forEach(function(option){
            var opt = document.createElement('option');
            opt.value = option.value;
            opt.innerText = option.label;
            me.dropdown.appendChild(opt);
        })
        me.dropdown.value = me.value;
    }
};



var opt1 = new OptResDropdown(optRes1);
var opt2 = new OptResDropdown(optRes2);
var opt3 = new OptResDropdown(optRes3);

OptResDropdown.instances.opt1 = opt1;
OptResDropdown.instances.opt2 = opt2;
OptResDropdown.instances.opt3 = opt3;

</script>
</body>
</html>

这应该可以正常工作我认为

答案 1 :(得分:0)

您将需要一个自定义序列化程序,它遍历父Map。对于每个嵌套Map,您只需使用writeObjectField键,值为字段名称和值。

您还需要自动序列化所有其他字段。您只能在字段上设置自定义序列化程序,但您仍然可以在JSON中获得data字段。实际上,您希望提升数据内容,使其看起来像Sample字段,并且需要Sample的自定义序列化程序。除了data字段之外,我能想到自动序列化其他所有内容的唯一方法是使用反射

以下序列化程序将在您的问题中生成JSON:

class SampleSerializer extends StdSerializer<Sample> {
    private static final List<Field> sampleFields;

    public SampleSerializer() { this(null); }
    private SampleSerializer(Class<Sample> t) { super(t); }

    static {
        sampleFields = Arrays.stream(Sample.class.getDeclaredFields())
                .filter(f -> !("data".equals(f.getName())))
                .collect(toList());
    }

    @Override
    public void serialize(Sample sample, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartObject();
        for (Field field : sampleFields) {
            try {
                field.setAccessible(true);
                jgen.writeObjectField(field.getName(), field.get(sample));
            } catch (IllegalAccessException ignored) {
            }
        }
        for (Entry<String, Map<String, Object>> entry : sample.getData().entrySet()) {
            jgen.writeObjectField(entry.getKey(), entry.getValue());
        }
        jgen.writeEndObject();
    }
}

您还必须指定SampleSerializer将用于Sample,例如通过注释该类:

@JsonSerialize(using = SampleSerializer.class)
class Sample {

答案 2 :(得分:0)

我想出了一种更简单的方法,可以在不使用自定义序列化程序的情况下完成此操作;这是@JsonAnyGetter和@JsonAnySetter。这是一个完整的例子。我正在粘贴关于粘贴在这里的样本的答案,因为它可能对其他人有用。

gacutil -l System.Data.SQLite 

Example