代码之家  ›  专栏  ›  技术社区  ›  brain storm

在Jackson中使用自定义序列化程序序列化嵌套对象时出现JsonGenerationException

  •  0
  • brain storm  · 技术社区  · 7 年前

    这是我想要序列化的类。

    public class ItemRow<T> {
    
        private String id;
        private List<T> items;
    }
    

    允许有两种变化。 ItemRow<String>, ItemRow<ItemRow> .

    ItemRow item1 = new ItemRow("abc", Arrays.asList("item1", "item2", "item3"));
    String result = mapper.writeValueAsString(item1);
    System.out.println(result);
    

    应该给

    {
         "abc":["item1","item2","item3"]
    }
    

    现在是后一种情况

    ItemRow item2 = new ItemRow("cde", Arrays.asList("item4, item5"));
    ItemRow item = new ItemRow("combined", Arrays.asList(item1,item2));
    result = mapper.writeValueAsString(item);
    System.out.println(result);
    

    {
        "combined": {
            "abc": ["item1", "item2", "item3"],
            "cde": ["item4", "item5"]
        }
    }
    

    但我在序列化后者时遇到异常。第一个按预期工作。所以我相信递归序列化失败了,但我无法找出原因

    这是个例外

    com.fasterxml.jackson.core.JsonGenerationException: Can not start an object, expecting field name (context: Object)
    
        at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1961)
        at com.fasterxml.jackson.core.json.JsonGeneratorImpl._reportCantWriteValueExpectName(JsonGeneratorImpl.java:244)
        at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._verifyValueWrite(WriterBasedJsonGenerator.java:866)
        at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeStartObject(WriterBasedJsonGenerator.java:279)
        at hello.ItemRowSerializer.serialize(ItemRow.java:58)
        at hello.ItemRowSerializer.serialize(ItemRow.java:42)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
        at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2655)
        at com.fasterxml.jackson.core.base.GeneratorBase.writeObject(GeneratorBase.java:381)
        at hello.ItemRowSerializer.serialize(ItemRow.java:67)
        at hello.ItemRowSerializer.serialize(ItemRow.java:42)
    

    class ItemRowSerializer extends JsonSerializer<ItemRow> {
    
        @Override
        public void serialize(ItemRow itemRow, JsonGenerator jgen, SerializerProvider serializerProvider) throws IOException {
    
            String id = itemRow.getId();
            List<Object> items = itemRow.getItems();
    
            if (items.isEmpty()) {
                jgen.writeStartObject();
                jgen.writeFieldName(id);
                jgen.writeStartArray();
                jgen.writeEndArray();
                jgen.writeEndObject();
            }
            else {
                jgen.writeStartObject();
                Object item = items.get(0);
                jgen.writeFieldName(id);
                if (item instanceof  ItemRow){
                    for (Object i : items) {
                        //ItemRow temp = (ItemRow) i;
                        //jgen.writeObjectField(temp.getId(), temp);
                        //jgen.writeObjectField(id, i);
                        jgen.writeStartObject();
                        jgen.writeObject(i);
                        jgen.writeEndObject();
                    }
                }
                else {
                    //jgen.writeFieldName(id);
                    jgen.writeStartArray();
                    for (Object arg : items) {
                        jgen.writeString(arg.toString());
                    }
                    jgen.writeEndArray();
                }
            }
            jgen.writeEndObject();
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Burak Akyıldız    7 年前

    您的序列化程序算法不正确。代码在上面。直接反序列化对象时,不需要启动对象。我删除了这些步骤并最小化了代码。

    示例测试;

    @Test
    public void serializeTest() throws JsonProcessingException
    {
        ObjectMapper mapper = new ObjectMapper();
    
        SimpleModule module = new SimpleModule();
        module.addSerializer(ItemRow.class, new ItemRowSerializer());
        mapper.registerModule(module);
    
        ItemRow item1 = new ItemRow("abc", Arrays.asList("item1", "item2", "item3"));
        String result = mapper.writeValueAsString(item1);
        System.out.println(result);
    
    
        ItemRow item2 = new ItemRow("cde", Arrays.asList("item4", "item5"));
    
    
        ItemRow item6 = new ItemRow("deeper-1", Arrays.asList("item6", "item7"));
        ItemRow item7 = new ItemRow("deeper-2", Arrays.asList("item6", "item7"));
        ItemRow item8 = new ItemRow("deeper", Arrays.asList(item6, item7));
    
        ItemRow item3 = new ItemRow("inner-1", Arrays.asList("item6", "item7"));
        ItemRow item4 = new ItemRow("inner-2", Arrays.asList("item6", "item7"));
        ItemRow item5 = new ItemRow("inner", Arrays.asList(item3, item4, item8));
    
    
    
    
        ItemRow item = new ItemRow("combined", Arrays.asList(item1,item2,item5));
        result = mapper.writeValueAsString(item);
        System.out.println(result);
    
    }
    

    public class ItemRowSerializer extends JsonSerializer<ItemRow>
    {
    
        @Override
        public void serialize(ItemRow itemRow, JsonGenerator jgen, SerializerProvider serializerProvider) throws IOException
        {
            jgen.writeStartObject();
            writeInnerObject(jgen, itemRow);
            jgen.writeEndObject();
        }
    
    
        private void writeStringArr(JsonGenerator jgen, List items) throws IOException
        {
            jgen.writeStartArray();
            for (Object arg : items)
            {
                jgen.writeString(arg.toString());
            }
            jgen.writeEndArray();
        }
    
    
        private void writeInnerObject(JsonGenerator jgen, ItemRow row) throws IOException
        {
            jgen.writeFieldName(row.getId());
    
            if (row.getItems().size() > 0 && row.getItems().get(0) instanceof ItemRow)
            {
                jgen.writeStartObject();
                for (int i = 0; i < row.getItems().size(); i++)
                {
                    ItemRow innerRow = (ItemRow) row.getItems().get(i);
                    if( innerRow.getItems().size() > 0 && innerRow.getItems().get(0) instanceof ItemRow )
                    {
                        writeInnerObject(jgen, innerRow);
                    }
                    else
                    {
                        jgen.writeFieldName(innerRow.getId());
                        writeStringArr(jgen, innerRow.getItems());
                    }
                }
                jgen.writeEndObject();
            }
            else
            {
                writeStringArr(jgen, row.getItems());
            }
        }
    }