Search code examples
javasimple-framework

Prevent inclusion of empty tag for an empty ElementList in an ElementListUnion


I have the following code in one of my classes:

@Text(required=false)
@ElementListUnion({
    @ElementList(required = false, inline = true, type = com.company.Child.class, entry="values")
})
public List<Object> valueUnion;

Note that this seems to be the only way to get the framework to work with elements that contain both children and text. This works great when text is present and the elementlist contains elements as well, and produces the following xml:

<parent>
    <values>val 1</values>
    <values>val 2</values>
    some text
</parent>

However, sometimes the element list contains no elements, with only the text being present (meaning the valueUnion List only contains one element, the string of text). This however, results in the following XML:

<parent>
    <values />
    some text
</parent>

And herein lies the problem, as this causes the server to choke over the empty <values /> tag. Unfortunately I do not have control over the code on the server, and I am looking for a way to force Simple to ignore the empty tag if the elementlist contains no elements.


Solution

  • I have a workaround for you. Its not beautiful, but the concept can help you here.
    Instead of element-annotations you can use a custom Converter which serializes your Objects.

    • Example Class:

    (Contains the list, the text and other elements you need)

    @Root(name="parent")
    @Convert(ExampleConverter.class)
    public class Example
    {
        private String text; // Save the text you want to set ('some text' in your code)
        private List<Object> valueUnion;
    
        // Constructor + getter / setter
    }
    

    Actually you only need the @Convert(ExampleConverter.class) and @Root Annotations here, since the serialization is done in your own converter (ExampleConverter).

    • ExampleConverter Class:

    (Serialize / Deserialize your Object here)

    public class ExampleConverter implements Converter
    {
        @Override
        public Object read(InputNode node) throws Exception
        {
            /* TODO: Deserialize your class here (if required). */
            throw new UnsupportedOperationException("Not supported yet.");
        }
    
    
        @Override
        public void write(OutputNode node, Object value) throws Exception
        {
            final Example val = (Example) value;
            final List<Object> l = val.getValueUnion();
    
            if( !l.isEmpty() ) // if there are elements, insert their nodes
            {
                for( Object obj : l )
                {
                    node.getChild("values").setValue(obj.toString());
                }
            }
            else
            {
                node.getChild("values").setValue(""); // this creates <values></values> if list is empty
            }
            node.setValue(val.getText()); // Set the text (1)
        } 
    }
    

    (1): This will set your text even if there are some other elements. However this solution may break your formating; the text and the closing tag will be on the same line. You can solve this by inserting a new line.

    • Usage:

    Create a serializer, et your strategy and write / read

    Serializer ser = new Persister(new AnnotationStrategy()); // 'AnnotationStrategy is important here!
    ser.write(...); // write / read
    
    • Examples:

    With elements in the list:

    Example t = new Example();
    t.setText("abc"); // Set the text
    t.getValueUnion().add("value1"); // Add some elements to list
    t.getValueUnion().add("value2");
    
    Serializer ser = new Persister(new AnnotationStrategy());
    ser.write(t, f); // 'f' is the file to write
    

    Output:

    <parent>
       <values>value1</values>
       <values>value2</values>abc</parent>
    

    Without elements in the list:

    Example t = new Example();
    t.setText("abc"); // Set the text
    
    Serializer ser = new Persister(new AnnotationStrategy());
    ser.write(t, f); // 'f' is the file to write
    

    Output:

    <parent>
       <values></values>abc</parent>
    

    Please notice the formating "problem" as said before!