Mittwoch, 23. Juli 2014

Requiring a constructor without arguments in Java

In Java every class gets a default constructor. This constructor has no arguments and it is possible to override this constructor. But it is also possible to define a constructor with arguments. In this case it is not possible any more to make an instance of this class without specifying the arguments for the constructor. Java does not create any default constructors as long as any constructor has been defined.

This leads to the problem: how to require a class to have a constructor without arguments?

In Java it is not possible to specify any rules for anything static. Anything static are either classes or static methods. It is neither possible to implement an interface with a static method, nor is it possible to define an interface for a class. Interfaces in Java specify requirements only for objects. Java does not implement a Meta Object Protocol. How to work around this problem?

It is necessary to move the constructor from the class to the object, because for the object it is possible to define requirements in the interface the class implements. But the solution is not obvious, because it is necessary to make the interface generic. Otherwise it would not be possible for the constructor method to return the correct type. Here is a complete example:

import java.util.List;
import java.util.LinkedList;

class Make
{
  static interface HasMake<T extends HasMake<?>>
  {
    T make();
  }

  static class Car implements HasMake<Car>
  {
    public Car make() { return new Car(); }
  }

  static class Bike implements HasMake<Bike>
  {
    public Bike make() { return new Bike(); }
  }

  public static void main (String[] args)
  {
    List<HasMake<?>> makeables = new LinkedList<HasMake<?>>();
    makeables.add (new Car());
    makeables.add (new Bike());
    for (HasMake<?> makeable : makeables)
      System.out.println (makeable.make());
  }
}

The interface which defines the constructor is HasMake and the constructor is called make. The interface has to be configured with itself. This makes it possible to use the correct return type in the prototype of make. The classes Car and Bike implement HasMake and as long as you have an instance of the classes it is possible to rely at compile time on the existence of the make method which creates a new instance of the class without arguments.

A solution using reflection will not guarantee this at compile time. It is possible to instantiate a class at run time using a constructor requiring no arguments. But it is not possible to require a class to have such a constructor. If it does not exist, the solution using reflection will fail at run time with an run time exception and it will be impossible to work around this exception at run time.

Dienstag, 8. Juli 2014

Subversion reintegrate without --reintegrate

Older Subversion servers do not support the --reintegrate option of newer clients. This makes it necessary to do it without. In order to merge the changes from a branch into the trunk it is necessary to find the revision number when the branch has been created by a copy. This is done by the --stop-on-copy option of svn log.

$ svn log --verbose --stop-on-copy ../branches/szi
------------------------------------------------------------------------
r3501 | szi | 2014-07-08 16:14:07 +0200 (Tue, 08 Jul 2014) | 1 line
Changed paths:
   A /java-dao/branches/szi (from /java-dao/trunk:3494)
   M /java-dao/branches/szi/src/dao/Condition.java
   M /java-dao/branches/szi/src/dao/Entity.java
   M /java-dao/branches/szi/src/dao/Factory.java
   M /java-dao/branches/szi/src/dao/Facturable.java
   M /java-dao/branches/szi/src/dao/Order.java
   M /java-dao/branches/szi/src/dao/Value.java

After that you can do the merge.

$ svn merge -r 3494:HEAD ../branches/szi
--- Merging r3495 through r3581 into '.':
U    src/dao/Factory.java
U    src/dao/Facturable.java
U    src/dao/Order.java
U    src/dao/Value.java
U    src/dao/Entity.java
U    src/dao/Condition.java