Yesterday, I discovered a funny nuance in Java programming language, which I didn’t know before and decided to share it with you. I was designing an API for transport of changes in relationships between two DTO types. Since I wanted to support batch changes, I created the class for carrying these:
class ManyToManyDelta<S extends BaseDto<?>, T extends BaseDto<?>> { List<SimpleRelationship<S,T>> relationshipsToAdd; List<SimpleRelationship<S,T>> relationshipsToRemove; ... } class SimpleRelationship<V extends BaseDto<?>, W extends BaseDto<?>> { // BaseDto classes are identified by the parameterized Id Id<V> left; Id<W> right; SimpleRelationship(BaseDto<V> one, BaseDto<W> another) { left = one.getId(); right = another.getId(); } }
Having this structure, you can model the relationship between two instances of types A and B by an instance of SimpleRelationship<A>
. If you want to communicate the creation of a relationship you would put the latter into the relatioshipToAdd
list, if you want to model the deletion, you would put it into the relatioshipToRemove
list.
Now I it was time to develop methods for access of the relationship lists inside of the ManyToManyDelta
:
class ManyToManyDelta<S extends BaseDto<?>, T extends BaseDto<?>> { ... public void add(SimpleRelationship<S, T> toAdd) { if (toAdd == null) { /* react */} this.relatioshipToAdd.add(toAdd); } ... }
You could think that you have a batch update (e.g. an Array
or List
) of SimpleRelatioship
objects you would like to add them by one invocation instead of a series of invocation. e.G:
class ManyToManyDelta<S extends BaseDto<?>, T extends BaseDto<?>> { ... public void add(SimpleRelationship<S, T>[] toAdd) { if (toAdd == null) { /* react */} this.relatioshipToAdd.addAll(Arrays.asList(toAdd)); } public void add(SimpleRelationship<S, T> toAdd) { if (toAdd == null) { /* react */} this.relatioshipToAdd.add(toAdd); } ... }
Using the varargs feature of Java you could also write equivalent:
class ManyToManyDelta<S extends BaseDto<?>, T extends BaseDto<?>> { ... public void add(SimpleRelationship<S, T>... toAdd) { if (toAdd == null) { /* react */} this.relatioshipToAdd.addAll(Arrays.asList(toAdd)); } ... }
That would be nice, right? By the way, it is a good idea, to write some client code, during the development of API. This discovers potential problems:
... A entityA = ...; B entityB = ...; ManyToManyDelta<A, B> delta = new ManyToManyDelta<A,B>(); delta.add(new SimpleRelationship<A,B>(entityA, entityB));
Coding this result in a type safety warning: A generic array of SimpleRelationship is created for a varargs parameter. Which reveals a problem in a Java language: you can not create an array of parameterized types. And resulting from this fact, you can not use that as varargs argument.
Finally, if you want to create convenience methods for one and many items, you have to do it in a old-fashined way, by providing overloaded methods. Or you can use another language, which does not have this problem. My favorite one is Scala. The explaination of why the example above is not working is given by Martin Odersky (the author of Scala) : The Origins of Scala