views:

126

answers:

5

I have a number of different representations of the same kind of object; let's call it a Thing. "Thing" is a marker interface. ThingFormat0, ThingFormat1, ThingFormat2 etc. are all JavaBeans that implement Thing. (Because they are JavaBeans, a JSON marshaller automatically converts them to and from JSON automatically.) ThingFormat1 has just a few members like name and id. ThingFormat2 has URI links to other Things. In ThingFormat3 has ThingFormat1 representations of those other things etc.

The JSON serializer knows how to convert a URI automatically. (It works for any class where you can use toString() and the constructor ClassName(String string) to convert.)

I want to have a ThingFormat0 that behaves like a URI but implements the marker interface Thing.

public class ThingFormat0 extends URI implements Thing {}

This does not work because URI is a final class and can't be subclassed.

The only way I can think of to do this is by making a decorator (a very degenerate sort of decorator as it doesn't add any functionality to URI). This is easy in some "duck-typed" languages but more of a pain in Java, because I have to wrap a URI and implement all the methods of URI that I need. Is there an easier way?

+1  A: 

You cannot subclass a final class. Period.

In the case of URI, it is almost certainly final for security reasons; i.e. to stop someone from breaking sandbox security by supplying a sneaky subtype of URI that (for example) allows it to subvert access control.

So yes, you'll need to use a wrapper or decorator or something like that.

Stephen C
+2  A: 

Two simple ways I can think of:

  • If you use Eclipse, you can have delegate methods for any field generated automatically.
  • Copy the source of URI into a new class named ThingURI.
FelixM
+1  A: 

Is there any reason the class can't use composition instead of inheritance?

public class ThingFormat0 implements Thing {
  private final URI uri;

  public ThingFormat0(String uri) { this.uri = URI.create(uri); }

  public ThingFormat0(URI uri) { this.uri = uri; }

  public URI getUri() { return uri; }

  @Override public String toString() {
    return uri.toString();
  }
}
McDowell
When Thing is a member of my Response class, the JSON serialization of Response is {"thing":{"uri":"http://whatever"}} instead of {"thing":"http://whatever"}.
Mark Lutton
A: 
// base class that handles delegation
class BaseThing implements Thing {

   BaseThing(String uri) { ... }

   BaseThing(URI uri) { ... }

   URI getURI() { ... }

   ...
}

class ThingFormat0 extends BaseThing {
   ...
}
ndp
A: 

You're finding this is difficult because your ThingFormat types are not URIs. They expose URIs and can correspond to URIs, but that does not make them URIs. Perhaps you're pining for implementation inheritance, but interface inheritance fails here because this is not a proper is-a relationship; it fails the LSP.

Consider, for example, whether a ThingFormat has a scheme or a fragment component, or if one can be resolved against some base URI. Those are facets and operations of URIs that don't have much to do with ThingFormat, whatever it happens to do.

seh