#5 subtype featue request

open
nobody
None
5
2007-08-22
2007-08-22
Dmitri Koulakov
No

I have an idea on improving simple-xml in element/class sub typing. As far as I understand attribute "class" is used to mention subclasses of annotated class, for example:
<example class="demo.Example">
<data/>
<example>
If we shall have info about all subclasses of mentioned class we could omit "class" attribute in xml and use @Root(name) of subclasses. I'm not sure but think it is possible to add to @Element, @ElementList and @ElementArray parameter with list of all subclasses of annotating element class. In case of unknown subclass we can still use "class" attribute.

I think it would be great to improve readability of xmls that simple reads and writes.

Discussion

  • Logged In: NO

    Interesting idea. One other feature you can use is the Strategy, this will allow you to manipulate the XML to your satisfaction without affecting the core framework. For example you could have a method like so:

    public class MyDecoratorStrategy implements Strategy {

    private Strategy delegate;

    public MyDecoratorStrategy(Strategy delegate) {
    this.delegate = delegate;
    }

    public Type getElement(Class field, NodeMap node, Map map) {
    if(field == SomeClass.class) || field == SomeOtherClass.class) {
    node.setAttribute("class", field.getName());
    }
    delegate.getElement(field, node, map);
    }

    public boolean setElement(Class field, Object value, NodeMap node, Map map) {
    delegate.setElement(field, value, node, map);

    if(field == SomeClass.class || field == SomeOtherClass.class) {
    node.setAttribute("class", null);
    }
    }
    }

    This is a pretty crap example of how to write an XML decorator with the strategy interface. However it does show what is possible.

    Niall

     
  • Logged In: YES
    user_id=1164275
    Originator: YES

    I'm not expressed my idea exactly. I understand the example you've posted, but for this function I need more. I need to change name of the element (when writing it) to the @Root(name) of the actual value class and be sure that element with this name will be read later with my hint of its class (subclass of declared).

     
  • Logged In: NO

    Can you provide an example to clarify it. Are you talking about something like:

    <com.example.ClassName foo="bar" >Some text here</com.example.ClassName>

    Niall

     
  • Logged In: YES
    user_id=1164275
    Originator: YES

    Yes. More precisely:

    <resources>
    <resource href ="abc.jpeg"/>
    <jar href="abcd.jar"/>
    </resources>

    @Root
    class Resources {
    @ElementList(inline=true)
    List<Resource> list;
    }

    @Root()
    @Subclasses(known={Jar.class})
    class Resource { ... }

    @Root()
    class Jar extends Resource { ... }

    And I'm trying to write Strategy in this way:
    public class SubclassStrategy implements Strategy {

    private Strategy delegate;

    public SubclassStrategy(Strategy delegate) {
    this.delegate = delegate;
    }

    protected Class getSubclassByName(Class field, String name) {
    Subclasses annot = (Subclasses)field.getAnnotation(Subclasses.class);
    if (annot != null) {
    Class[] subclasses = annot.known();
    if (subclasses != null) {
    for (Class subclass: subclasses) {
    String element_name = getElementName(subclass);
    if (element_name.equals(name)) return subclass;
    }
    }
    }
    return null;
    }

    protected String getElementName(Class _class) {
    String name = null;
    Root annot = (Root)_class.getAnnotation(Root.class);
    if (annot != null) name = annot.name();
    if (name==null || name.length()==0) {
    name = _class.getSimpleName();
    name = name.substring(0,1).toLowerCase()+name.substring(1);
    }
    return name;
    }

    public Type getRoot(Class field, NodeMap node, Map map) throws Exception {
    Class subclass = getSubclassByName(field, node.getName());
    if (subclass != null) node.put("class", subclass.getName());
    return delegate.getRoot(field, node, map);
    }

     
  • Logged In: NO

    Actually, this idea seems pretty cool. I was thinking of augmenting the existing annotations such as

    public interface @ElementList {

    // etc...

    public Class[] candidates() default {}
    }

    In this way a schema can specifically suggest the subtypes allowed for a field or method, while still allowing the class schema to restrict the number of subtypes allowed. For example I could do the following.

    @Root
    public class MySchema {

    @Element(candidates={SubClassA.class, SubClassC.class})
    private BaseClass value;

    @Element(candidates={SubClassB.class, SubClassC.class})
    private BaseClass value;
    }

    @Root
    public class BaseClass {

    @Attribute
    private String href;
    }

    This will allow the following to be generated.

    <mySchema>
    <a href="xx"/>
    <b href="yy"/>
    <mySchema>

    Although it occurs to me there is a higher possibility of collisions between root names and field names, which is not so intuitive. For instance when compiling the schema and I have two elements of the name "a", one from the candidate class and one as the field declaration. How do I resolve this during deserialization, which does "a' map to. I guess it should just be like everything else, such that it is not allowed to have a candidate root name to be the same as any other candidate root or any other field in the class? Any thoughts?

    Niall

     
  • Logged In: YES
    user_id=1164275
    Originator: YES

    I agree that implementing this can lead to collisions but 'candidates' option could be helpful
    (as you've pointed this could be only @ElementList option). Will be glad to see this in future releases.