Search code examples
javaxmlserializationsimple-framework

How to create inner children without creating another class?


I need to generate an XML like this:

<Root>
   <Children>
      <InnerChildren>SomethingM</InnerChildren>
   </Children>
</Root>

The simplest solution is creating an inner class on the Root class:

@Root
class Root{
    @Element
    Children element;

    @Root
    private static class Children{
        @Element
        String innerChildren;
    }
}

But I want to avoid that inner class creation, since it will make things look strange while using Root objects. Is there anyway I can achieve that result without using inner classes?

Expected way to create Root objects:

Root root = new Root("Something");

What I want to avoid:

Children child = new Children("Something");
Root root = new Root(child);
// this could be achieve by injecting some annotations
// in the constructor, but it's awful

Solution

  • Just use a normal class instead of an inner class. It should still work:

    @org.simpleframework.xml.Root
    public class Root{
        @Element
        Children children;
    
        public Root(){
            children = new Children("Something");
        }
    }
    
    @org.simpleframework.xml.Root
    public class Children{
        @Element
        String innerChildren;
    
        public Children(String inner){
            innerChildren = inner;
        }
    }
    

    Update: If you do not want to create another class, you can use the Path annotation by specifying an XPath expression for the innerChildren field. For example:

    @org.simpleframework.xml.Root
    class Root {
       @Element
       @Path("children")
       private final String innerChildren;
    
       public Root(String name){
           innerChildren = name;
       }
    }
    

    Produces:

    <root>
       <children>
          <innerChildren>Something</innerChildren>
       </children>
    </root>
    

    Use the Namespace annotation to add name spaces. For example:

    @org.simpleframework.xml.Root
    @Namespace(reference="http://domain/parent", prefix="bla")
    class Root {
       @Element
       @Path("bla:children")
       @Namespace(reference="http://domain/parent", prefix="bla")
       private final String innerChildren;
    
       public Root(String name){
           innerChildren = name;
       }
    }
    

    Produces:

    <bla:root xmlns:bla="http://domain/parent">
       <bla:children>
          <bla:innerChildren>Something</bla:innerChildren>
       </bla:children>
    </bla:root>
    

    If using Styles to format the XML, it's necessary to do some modifications since they remove the : from the Element. The result using styles is:

    <bla:root xmlns:bla="http://domain/parent">
       <blachildren>
          <bla:innerChildren>Something</bla:innerChildren>
       </blachildren>
    </bla:root>
    

    This is what I did:

    public class MyStyle extends CamelCaseStyle{
        @Override
        public String getElement(String name) {
            if( name == null ){
                return null;
            }
            int index = name.indexOf(':');
            if( index != -1 ){
                String theRest = super.getElement(name.substring(index+1));
                return name.substring(0, index+1)+theRest;
            }
            return super.getElement(name);
        }
    }
    

    And now the result is the expected one:

    <bla:Root xmlns:bla="http://domain/parent">
       <bla:Children>
          <bla:InnerChildren>Something</bla:InnerChildren>
       </bla:Children>
    </bla:Root>