JAVA FAIL

Thursday, November 6, 2008

INTERFACE ENCAPSULATION FAIL

Let's say we have some existing useful library classes:

class LowLevelException extends Exception
{
private static final long serialVersionUID = 1L;
}

class Base
{
// Connect to the resource or throw if we can't
public Base(final String resourceName)
throws LowLevelException
{ /*...*/ }
}


Now, let's use that nice code to build some higher-level library

class Foo extends Base
{
// A higher-level API that can work with a preferred resource, but if it
// can't get it, will take a lesser-quality resource.
public Foo()
throws LowLevelException
{
try {
// Try to get the good stuff
super("Preferred Resource");

} catch(final LowLevelException ex) {
// Get by with this
super("Fall-back Resource");
}
}
}


But we can't do that:

$ javac -Xlint:all Foo.java
Foo.java:18: cannot find symbol
symbol : constructor Base()
location: class Base
{
^
Foo.java:21: call to super must be first statement in constructor
super("Preferred Resource");
^
Foo.java:25: call to super must be first statement in constructor
super("Fall-back Resource");
^
3 errors


Zomg! So this means you can't catch exceptions from your base class constructor(s) and deal with them locally?

It would seem that it also prevents you from translating an exception from a base class constructor in your derived class constructor.

class HighLevelException extends Exception
{
private static final long serialVersionUID = 1L;
}

class Foo2 extends Base
{
// A higher-level API that has some better way to represent the low-level
// exception, perhaps simply by adding more detail about the failure.
public Foo2()
throws HighLevelException
{
try {
super("Something");

} catch(final LowLevelException ex) {
throw new HighLevelException("More detail", ex);
}
}
}


$ javac -Xlint:all Foo.java
Foo.java:43: cannot find symbol
symbol : constructor Base()
location: class Base
{
^
Foo.java:45: call to super must be first statement in constructor
super("Something");
^
Foo.java:48: cannot find symbol
symbol : constructor HighLevelException(java.lang.String,LowLevelException)
location: class HighLevelException
throw new HighLevelException("More detail", ex);
^
3 errors


Yeah, cause why would I ever want to do that? I dunno, perhaps to make a clean API encapsulates its dependencies? *sigh*