Java method chaining and auto-cast

Posted in auto-cast, java, method chaining, polymorphism, programming on May 19, 2008 by adi11235

I stumbled into an interesting problem while playing around with java method chaining.

Basically, we have an object with a number of properties. We want to assign those properties in an inline manner.

Example:
MyType t = new MyType();
t.setA("a");
t.setB("b");
t.setC("c");
t.setD("d");

Doing the same through method chaining:
MyType t = new MyType().setA("a").setB("b").setC("c").setD("d");

This is possible because the types of setA(), setB(), … are the same as MyType.

This is how the implementation of MyType would look:

public class MyType {
private String a, b, c, d;

//constructor
public MyType() {
a = ""; b = ""; c = ""; d = "";
return this; //return back the current object
}

public MyType setA(String s) {
a = s;
return this;
}

public MyType setB(String s) {
b = s;
return this;
}

public MyType setC(String s) {
c = s;
return this;
}

public MyType setD(String s) {
d = s;
return this;
}

}

As you see, each method returns its own object at the end of the call so that the other methods can pick up and complete the chain.

Well, this works fine and dandy, but what about derived classes?

The wrong way to do it in java:

public class MyDerivedType extends MyType {
private String e;

//constructor
public MyDerivedType () {
super(); //We call the constructor of MyType
e = "";
}

public MyDerivedType setE(String s) {
e = s;
return this;
}
}

Use example:
MyDerivedType t = new MyDerivedType().setA("a")...

This throws an exception because it can’t find a method called setA(). That’s because the return type of setA remains MyType and it’s not MyDerivedType.

In order to address this problem, we may do this:

MyDerivedType t = (MyDerivedType)(new MyType().setA("a").setB("b"));

That is, we use our original type, then we cast the result to MyDerivedType.

That is a bad solution because we have to keep track of our supertypes at all times and that we get the ugliness of casts. The problem is compounded when we need to mix methods of the supertype with methods of derived types:

MyDerivedType t = ((MyDerivedType)(new MyType().setA("a").setB("b"))).setE("e");

What we have is an inability of java to cast types into their derived classes. That is, we cannot auto-cast from MyType to MyDerivedType:

MyDerivedType t = new MyType(); //throws an exception, incompatible types

So our solution is to manually override all the methods of the superclass into the derived classes:

public class MyDerivedType extends MyType {
private String e;

//constructor
public MyDerivedType () {
super(); //We call the constructor of MyType
e = "";
}

//Override notation to help readability, we can do without it, though
@Override
public MyDerivedType setA(String s) {
return (MyDerivedType)super.setA(s);
}

@Override
public MyDerivedType setB(String s) {
return (MyDerivedType)super.setB(s);
}

@Override
public MyDerivedType setC(String s) {
return (MyDerivedType)super.setC(s);
}

@Override
public MyDerivedType setD(String s) {
return (MyDerivedType)super.setD(s);
}

public MyDerivedType setE(String s) {
e = s;
return this;
}
}

With this, we can do:

MyDerivedType t = new MyDerivedType().setA("a").setB("b").setC("c").setD("d")
.setE("e");

It’s all nice and clean and this is how you should do it in Java.

However, there is still a small code duplication problem involved with all this overriding. It would be much easier if Java had auto-cast from derived types. Such a feature would not break type safety since we’re not casting from arbitrary types.

Web services in Netbeans (Video tutorial)

Posted in java, netbeans, tutorials, video, web service on May 10, 2008 by adi11235

SGML, HTML and XML (Video tutorial)

Posted in DTD, html, sgml, tutorials, video, xml on May 9, 2008 by adi11235

This old guy does a good job explaining things.

Part 1

Part 2

XSLT

Posted in xml, xslt on April 20, 2008 by adi11235

A more in-depth description of my recent experience with XSLT will be forthcoming. But until then, gaze your eyes at this:

99bottles.xml

99bottles.xsl

(copy both files in one folder and open 99bottles.xml with a web browser)