Problem trying to generate XML with dynamic list entry tags
I am trying to generate a XML payload for an API that uses a XML based query language. I have something similar to the following code:
public class JacksonTest
{
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
@JsonSubTypes.Type(value = And.class, name = "and"),
@JsonSubTypes.Type(value = Or.class, name = "or"),
@JsonSubTypes.Type(value = EqualTo.class, name = "equalto"),
})
public interface Filter {
}
public static class And implements Filter {
@JacksonXmlElementWrapper(useWrapping = false)
protected List<Filter> filter;
}
public static class Or implements Filter {
@JacksonXmlElementWrapper(useWrapping = false)
protected List<Filter> filter;
}
public static class EqualTo implements Filter {
protected String field;
protected String value;
}
@JacksonXmlRootElement(localName = "query")
public static class MyQuery {
@JacksonXmlElementWrapper(useWrapping = false)
protected List<Filter> filter;
}
public static void main(String[] args) {
MyQuery myQuery = new MyQuery();
myQuery.filter = new ArrayList<>();
EqualTo equalTo = new EqualTo();
equalTo.field = "WHENMODIFIED";
equalTo.value = "05/14/2020 17:09:33";
And and = new And();
and.filter = new ArrayList<>();
and.filter.add(equalTo);
myQuery.filter.add(and);
}
}
and the payload I need would be:
<query>
<filter>
<and>
<equalto>
<field>WHENMODIFIED</field>
<value>05/14/2020 17:09:33</value>
</equalto>
</and>
</filter>
</query>
but the payload I currently get is:
<query>
<filter>
<and>
<filter>
<equalto>
<field>WHENMODIFIED</field>
<value>05/14/2020 17:09:33</value>
</equalto>
</filter>
</and>
</filter>
</query>
I've already looked everywhere but couldn't figure out how I can convince my And entity to skip the filter tag.
This might be related to #230 but I got recommended to create a new ticket.
Right, the format you get is what Jackson will produce with WRAPPER_OBJECT: <filter> is for List entry and <equalto> is the Type Id "wrapped" around value.
There is currently no way to combine entry and type id into one tag: this is one of 3 Type Id inclusion methods that work with XML module (other two PROPERTY and EXISTING_PROPERTY would add Type Id as separate level with other properties).
So ability to do something like you want would need to be a new feature.
Is there any way that I can simulate/work around this with some form of custom serializer?
@fkrauthan Type Id handling is implemented by TypeSerializer and TypeDeserializer which delegate to value (de)serializers, so that would theoretically be the place. Unfortunately the problem is specifically that Type(De)Serializer outputs outermost element, and then value Json(De)Serializer innermost. There would have to be some mechanism to "flatten" the two (or suppress one of them).
This if modular composition of pieces is to be supported: for brute force solution it would of course be possible to create (de)serializers that simply combine all aspects (container and element (de)serialization, type handling) and which could produce exactly whatever structure is needed. That would be more work but could conceivably solve specific problem for you (without offering general solution for others).
That might potentially lead to more general solution too -- something that would not integrate fully with @JsonTypeInfo, but that could be used in cases where this exact structure (which is what JAXB produces/consumes if I'm not mistaken) has to be used.
So if I understand you correctly I could write a custom Serializer for my And class that calls for each element of the field list the jgen.writeObject(listItem); and jackson should auto convert that to the correct JsonSubTypes translated element tag directly as a child of <and> XML Tag? Or is that also not something that would work?
@fkrauthan I am not sure that would work, since that would still try to call TypeSerializer and JsonSerializer (JsonSubTypes information is handled by TypeSerializer).
What would be needed would be replacement of calls they make, omitting ones you do not want, reimplementing most of logic. It could be relatively simple since you only need to handle exact use case for your types and no configuration, or having to worry about many other complications that happen in general case (wrt different dataformat, every feature Jackson offers that you do not use etc etc).
Quick note: #197 is for supporting JAXB-style flattened/condensed type ids. No current idea or plan of how to implement, but it is a known gap.