Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print custom sequence of tag using jackson databind lib in java?

I am using Jackson XML annotation to serialize/deserialize xml output of my spring boot APIs. This API is meant to provide legacy support. Because of that, it's required to have the exact same response structure as a new API as well. I encountered a peculiar situation for which I could not find any solution. I tried customSerilizer but that also doesn't seem to solve the problem.

I need to serialize A and B tags into pairs without any parent tags. The existing XML serilizes data in this format.

<Item>
  <SNO>22656565</SNO>
  <Weight>0.0</Weight>
  <A>data1</A>
  <B>foo1</B>
  <A>data2</A>
  <A>data3</A>
  <B>foo3</B>
  <A>data4</A>
  <A>data5</A>
  <A>data6</A>
  <B>foo6</B>
</Item>

The java pojo look like this:


@Data
@JacksonXmlRootElement(localName = "Item")
@JsonPropertyOrder({"SNO", "Weight", "A", "B"})
public class Item {

    @JacksonXmlProperty(localName = "SNO")
    private String sNo;
    
    @JacksonXmlProperty(localName = "Weight")
    private Float weight;
    
    @JacksonXmlProperty(localName = "A")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<String> aList;
    
    @JacksonXmlProperty(localName = "B")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<String> bList;
}

Note: through a CustomSerializer I was able to read this data but serilization cannot be done. Whatever I try at the end all of A and B tags are grouped after serialization.

Could you please help in finding any solution to serialize this case? Thanks in advance.

like image 578
rahulkesharwani Avatar asked Dec 30 '25 15:12

rahulkesharwani


1 Answers

It is possible to serialize your Item object with the alternate A and B tags in your xml file with a custom serializer, so if you use the provided Item class you can directly add a JsonSerialize annotation over your class and it will work fine with the constraint of the same size of the two not null lists like you have specified:

@JsonSerialize(using = ItemSerializer.class) //<-- here the new annotation
@Data
@JacksonXmlRootElement(localName = "Item")
@JsonPropertyOrder({"SNO", "Weight", "A", "B"})
public class Item {

    @JacksonXmlProperty(localName = "SNO")
    private String sNo;

    @JacksonXmlProperty(localName = "Weight")
    private Float weight;

    @JacksonXmlProperty(localName = "A")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<String> aList;

    @JacksonXmlProperty(localName = "B")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<String> bList;
}

So you can define a new class extending the StdSerializer providing the alternate writing of A and B tags for your lists:

public class ItemSerializer extends StdSerializer<Item> {

    public ItemSerializer() {
        super(Item.class);
    }

    @Override
    public void serialize(Item value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        jgen.writeStartObject();
        jgen.writeStringField("SNO", value.getSNo());
        jgen.writeNumberField("Weight", value.getWeight());
        List<String> aList = value.getAList();
        for (int i = 0; i < aList.size(); ++i) {
            jgen.writeStringField("A", aList.get(i));
            jgen.writeStringField("B", value.getBList().get(i));
        }
        jgen.writeEndObject();
    }
}

The expected result will be produced like below:

Item item = new Item();
item.setSNo("22656565");
item.setWeight(0.0f);
List<String> aList = List.of("data1", "data2", "data3");
item.setAList(aList);
List<String> bList = List.of("foo1", "foo2", "foo3");
item.setBList(bList);
String s = xmlMapper.writeValueAsString(item);
System.out.println(s);

Output:

<Item>
  <SNO>22656565</SNO>
  <Weight>0.0</Weight>
  <A>data1</A>
  <B>foo1</B>
  <A>data2</A>
  <B>foo2</B>
  <A>data3</A>
  <B>foo3</B>
</Item>
like image 180
dariosicily Avatar answered Jan 02 '26 12:01

dariosicily