2

I am trying to implement a class representing an XML tree as follows:

    public class XML<T extends XML<T>> {

        private final List<MarkupLanguage> nodeList = new ArrayList<>();

        private final Map<String, String> attributeList = new HashMap<>();

        public T attr(final String key, final String value) {
            if (value != null) {
                this.attributeList.put(key, value);
            } 
            return (T) this;
        }

        public T appendTo(final T node) {
            node.add(this);
            return (T) this;
        }
        ...
    } 

My problem is typing of these clauses - I am getting unchecked cast for "return (T) this;"

and also when I try to use the XML class by itself:

    final XML url = new XML("url");
    new XML("loc")
        .add("http://goout.cz")
        .appendTo(url);

I am getting:

    Unchecked cast to call appendTo(T) as a member of raw type XML.

How can I improve my code to get better typing?

4
  • What are you trying to achieve with XML<T extends XML<T>>? Commented Oct 13, 2012 at 1:08
  • @BheshGurung: probably as a "self type", to be able to for an instance to refer to its own type Commented Oct 13, 2012 at 4:32
  • 1
    related: stackoverflow.com/questions/7354740/… Commented Oct 13, 2012 at 20:44
  • Paul Bellora: This is exactly answer I was looking for. Commented Oct 14, 2012 at 6:15

2 Answers 2

5

Just type it:

final XML<T> url = new XML<T>("url");
new XML<T>("loc")
    .add("http://goout.cz")
    .appendTo(url);

It also looks like you really want to use XML<T> for your methods, not T, so you can avoid the casts (but I could be wrong):

public XML<T> attr(String key, String value) {
    if (value != null) {
        this.attributeList.put(key, value);
    } 
    return this;
}

public XML<T> appendTo(XML<T> node) {
    node.add(this);
    return this;
}
Sign up to request clarification or add additional context in comments.

3 Comments

I think he wants to do something like class XMLSubclass extends XML<SMLSubclass> and then be able to do XMLSubclass foo = new XMLSubclass("loc").add("http://goout.cz").appendTo(url); He wouldn't be able to do this with your method.
Yes, he is wanting the return type to be of the subclass for the methods. This example isn't very good at showing what his intentions of the return type is.
I really need to have public T appendTo as when I inherit for instance class HTML extends XML<HTML>, I need to have a return type HTML.
0

What about the approach below (simple inheritance plus generic methods):

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class XmlTest {

    @Test
    public void test() {
        XMLFirstSubclass url = new XMLFirstSubclass("url");
        XMLSecondSubclass xmlSecondSubclassInstance = new XMLSecondSubclass(
                "loc").add("http://goout.cz").appendTo(url);
    }
}

abstract class XML {

    private final List<String> texts = new ArrayList<String>();

    private final List<XML> nodes = new ArrayList<XML>();

    private final String nodeName;

    protected XML(String nodeName) {
        this.nodeName = nodeName;
    }

    @SuppressWarnings("unchecked")
    public <R extends XML> R add(String text) {
        texts.add(text);
        return (R) this;
    }

    @SuppressWarnings("unchecked")
    public <R extends XML, T extends XML> R add(T node) {
        nodes.add(node);
        return (R) this;
    }

    @SuppressWarnings("unchecked")
    public <R extends XML, T extends XML> R appendTo(T node) {
        node.add(this);
        return (R) this;
    }
}

class XMLFirstSubclass extends XML {
    public XMLFirstSubclass(String nodeName) {
        super(nodeName);
    }
}

class XMLSecondSubclass extends XML {
    public XMLSecondSubclass(String nodeName) {
        super(nodeName);
    }
}

Note that the generic methods allow to get a node from one type T and return the instance's type R, which can be different than the argument's type. T can be different than R, but both inherit XML.

Comments about the approach presented in the question

The approach that you're using until now can lead to strange situtations. Let's illustrate this with an example.

Below, we try to write the first class that specializes XML:

public class XMLFirstSubclass extends XML<OtherXMLSubclass> { ... }

If we're writing the first XML subclass, the only possible values to OtherXMLSubclass is XMLFirstSubclass or not declaring the generic type at all.

First option:

public class XMLFirstSubclass extends XML<XMLFirstSubclass> { ... }

Second:

public class XMLFirstSubclass extends XML { ... }

If you chose to use generics in your class design, the second option seems bad.
Taking a closer look into the first option, it opens the possibility of getting subclasses like:

class XMLSecondSubclass extends XML<XMLFirstSubclass> {
    ... 
}

Note that this compiles perfectly, but will cause class cast exceptions in XMLSecondSubclass method calls at runtime.

1 Comment

umm... what about public class XMLFirstSubclass extends XML<XMLFirstSubclass>?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.