Java

Default methods aspect oriented programming on JPA entities

When working with entity classes it is common not to add additional logic to the objects. This avoids dependencies in the code to keep it modular and maintainable. With default methods it is possible to enhance the entities in a simple way without affecting the original notion of a business object that just keeps the data.

Usually the entities are loaded from a database via the persistence layer, and are then used within the runtime context of the application. Modern frameworks provide descriptive mechanisms to define which entity attributes are to be displayed within the controls of the user interface.

public class Person {

    @NotNull
    @Size(min = 3, max = 40)
    private String firstName;
    private String name;
    
    @NotNull
    private Date birthday;

}

If the Person entity is to be displayed in a GUI the programmer only declares the columns of the table with the names of the class attributes. Modern frameworks then automatically load the values from the databean and display them in the user interface.

  public Date getBirthday() {
     return birthday;
  }
  
  public int getAgeInYears() {
     long ageInMillis = System.currentTimeMillis() - getBirthday().getTime();
     Calendar cal = Calendar.getInstance();
     cal.setTimeInMillis(ageInMillis);
     return cal.get(Calendar.YEAR);
  }

In the above example the age of a person is an aspect of the person class that can be derived from the current date and the persons birthday. Adding such a method will enable the framework to also show the current age. However it is these kind of methods that make the code harder to maintain as they are usually scattered around in several places of code. At best the developers have managed to put them into a common utility class. (which is used as a library in different versions throughout the project..) .

To generally avoid adding logic to the entity class by introducing a getter as shown one declares it as an adapter in the GUI logic. That way the birthday is converted to the age by the presentation layer.

interface AgeAspect {
  
  Date getBirthday();
  
  /**
   * See also 
   * {@linkplain https://stackoverflow.com/questions/1116123/how-do-i-calculate-someones-age-in-java}
   * @return the age in years relative to today
   */
  default int getAgeInYears() {
     long ageInMillis = System.currentTimeMillis() - getBirthday().getTime();
     Calendar cal = Calendar.getInstance();
     cal.setTimeInMillis(ageInMillis);
     return cal.get(Calendar.YEAR);
  }	
}

public class Person implements AgeAspect {

    @NotNull
    @Size(min = 3, max = 40)
    private String firstName;
    private String name;
    
    @NotNull
    private Date birthday;

    public Date getBirthday() {
       return birthday;
    }
}

With the new default methods introduced in Java 8 one can enhance every class that has a getBirthday() method can be amended with the age aspect by simply implementing the interface and without breaking any existing inheritance hierarchies.

The Viritin library that adds functionality for JPA entities in the Vaadin web app gui framework will soon have support for default methods, see pull request here.

Currently most frameworks do not support calling the default methods and the introspection only determines normal properties of classes. However the regular reflection api introduced in Java 4 is fully sufficient to implement this functionality therefore the libraries supporting it are still compatible with older Java releases.

Hopefully more library implementations such as the apache commons beanutils will support default methods soon.

The right Java bytecode version for Android

Android up to API level 23 does not support all possibilities of Java 8, the classes that the compiler generates have a version flag to denote which bytecode extensions can be inside of it. If you ever happen to hit an error like this during your build

UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.RuntimeException: Exception parsing classes
        at com.android.dx.command.dexer.Main.processClass(Main.java:752)
        at com.android.dx.command.dexer.Main.processFileBytes(Main.java:718)
        at com.android.dx.command.dexer.Main.access$1200(Main.java:85)
        at com.android.dx.command.dexer.Main$FileBytesConsumer.processFileBytes(Main.java:1645)
        at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
        at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
        at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
        at com.android.dx.command.dexer.Main.processOne(Main.java:672)
        at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
        at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
        at com.android.dx.command.dexer.Main.run(Main.java:277)
        at com.android.dx.command.dexer.Main.main(Main.java:245)
        at com.android.dx.command.Main.main(Main.java:106)
Caused by: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
        at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
        at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
        at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
        at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
        at com.android.dx.command.dexer.Main.parseClass(Main.java:764)
        at com.android.dx.command.dexer.Main.access$1500(Main.java:85)
        at com.android.dx.command.dexer.Main$ClassParserTask.call(Main.java:1684)
        at com.android.dx.command.dexer.Main.processClass(Main.java:749)
        ... 12 more
1 error; aborting

:app:transformClassesWithDexForDebug FAILED

you most likely included a class generated with a compiler target-level that was too advanced ( 34 hexadecimal in the case above is the level 52 of the Java 8 class format).
Android as of today supports all features of the JDK 7 compiler (see e.g. the release notes of the ADT plugin https://developer.android.com/tools/sdk/eclipse-adt.html).

In order to actually find the classes that were compiled against the wrong Java version you can use this command and check for anything that is >= 52

javap -v *.class | grep major 
# it'll report e.g.:
  major version: 50

To define which Java bytecode compatibility level to use and still have the latest jdk8 in your JAVA_HOME, you can use this in the build section of your Maven pom:

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>

 

The Gradle Java plugin is configured like this (the compatibility definition needs to be after applying the java plugin to take effect and gradle-android projects have this stored in the compileOptions instead as shown below)

allprojects {
    apply plugin: 'java'
    sourceCompatibility = 1.7
    targetCompatibility = 1.7
}

// Gradle-Android projects have this stored in the compileOptions instead:
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
    // [..]
}

Source and target compatibility are usually set to the same level, you need to be careful and should know what you are doing if you set them to different values, for example linkage errors at runtime may occur if the classes refer to newer java apis that were not present earlier.

Spliterator for “in-between” lambda processing

The usecase of summing up the distances in a list of vectors can benefit from parallelization on todays multi-core systems with Java 8 lambdas using a Spliterator.

If one writes

vecList.stream().mapToDouble( e-> 
    e.getDistance( b )

Then a reference to the next point “b” isn’t there hence the calculation cannot be performed that way. There is a property of each list item, it has a relation to the previous and a relation to the next item in the list.

Expressed as a piece of java code it might look as simple as this

final class Relation<T> {
   private final T a;
   private final T b;
   public Relation(T t0, T t1) {
      this.a = t0;
      this.b = t1;
   }
   public T getA() {
      return a;
   }
   public T getB() {
      return b;
   }
}

If we iterate on the relation organizing the list items into pairs, a distance calculation is possible by using a lambda expression and the stream api.

double totalDistance = stream.mapToDouble(
   e -> {
      return e.getA().distance(e.getB());
   }).sum();

To get there, a Spliterator class has to be defined that provides items for processing when the lambda expression is evaluated and is also capable of dividing the remaining set of items into subsets (sub-lists in this case) for parallel processing. Here is a possible implementation:

/**
 * A provider for pairs of consecutive list items
 *
 * @param <T>
 */
public class PairIterator<T> implements Spliterator<Relation<T>> {

 private final List<T> list;

 private int index;
 private final int start;
 private int end;
 
 /**
  * Allows to iterate over elements and their successors
  */
 public PairIterator(List<T> list) {
    this(list, 0, list.size());
 }

 /**
  * Internally used when the iterator is being split
  */
 private PairIterator(List<T> list, int start, int end) {
    this.list = list;
    this.start = index = start;
    this.end = end;
 }
 /**
  * Creates a new Relation between two consecutive items and 
  * performs the {@link Consumer#accept(entry)} operation. 
  */ 
 @Override
 public boolean tryAdvance(Consumer<? super Relation<T>> action) {
    Relation<T> entry;
    if (index >= end || index >= list.size()-1) {
       return false;
    }
    entry = new Relation<T>(list.get(index), list.get(++index));
    action.accept(entry);
    return true;
 }

 /**
  * If the list still has more that 4 elements to be processed
  * the method splits the work items into two working sets of ordered elements
  */ 
 @Override
 public PairIterator<T> trySplit() {
    int size = end - index;
    if (size > 4) {
       //reuse the middle element for both sides, so pair(mid-1,mid) and pair(mid,mid+1) is created 
       int mid = start + (size >> 1);
       int prevEnd = end;
       end = mid;
       return new PairIterator<T>(list, mid, prevEnd);
    }
    return null;
 }
 /**
  * @return the size of the remaining workload
  */
 @Override
 public long estimateSize() {
    return (end - index);
 }
 /**
  * Configuration of this spliterator
  */
 @Override
 public int characteristics() {
    return Spliterator.CONCURRENT | Spliterator.SIZED | Spliterator.ORDERED;
 }
}

There are two methods in the Spliterator implementation that are used to accomplish streaming the relations of predeccessor and successor, tryAdvance and trySplit. The first actually performs the action on the item pair by instantiating a Relation  on-the-fly, and calling accept(...) where the real calculation happens. The latter contains the algorithm to distribute the workload to the consumers. If the size of the remaining elements is greater than 4 it changes the indeces pointing into the list and returns a new instance configured for the remaining indeces. The method is designed to have a list element being used in two relations, once as a sucessor and once as a predecessor, so care must be taken not to modify its state by executing code with side-effects.

To use it a Stream is constructed with the StreamSupport class by passing the Spliterator as an argument and true to ensure it is processed in parallel:

//creates a parallel stream
Stream<Relation<Vec2>> stream = StreamSupport.stream(new PairIterator<Vec2>(vecList), true);

double totalDistance = stream.mapToDouble(
  e -> {
     return e.getA().distance(e.getB());
  }).sum();

 

Generic interfaces and algorithms

A common pattern in object oriented programming is interfacing classes that have the same methods. If these classes encapsulate a datatype and expose  methods that take the datatype as a parameter, generic interfaces. The approach results in the ability to apply a generic algorithm on different encapsulated data types.

For example vector math classes have this property, they can be defined for double and float datatypes and also for 2- and 3-dimensional implementations with methods for doing common operations.

public final class Vec3 implements Vec<Vec3> {
  private double x;
  private double y;
  private double z;

  /**
   * returns the distance to another vector
   * @param other the other vector
   * @return distance
   */
   public final double distance(Vec3 other) {
      return Math.sqrt(
        (x-other.x)*(x-other.x)+
        (y-other.y)*(y-other.y)+
        (z-other.z)*(z-other.z));
   }
}

public final class Vec2 implements Vec<Vec2> {
  private double x;
  private double y;
 
  /**
   * returns the distance to another vector
   * @param other the other vector
   * @return distance
   */
   public final double distance(Vec2 other) {
      return Math.sqrt(
        (x-other.x)*(x-other.x)+
        (y-other.y)*(y-other.y));
   }
}

The generic interface that both classes implement can then be declared like this:

public interface Vec<V> {
   double distance(V other);
}

It can contain all functions that have the same ‘abstract’ method signature that the classes have in common, ie. the more complicated cross product that returns a vector again.

The real benefit of this is not immediately obvious, consider adding up the distances of a list of items – one would naively just implement the method for each vector type Vec2 and Vec3. This results in duplicate code, reduced maintainability and is errorprone.

A class holding the algorithms operating on the Vec<V> interface can be used instead, the method needs to make use of the disance(V) method to determine the overall distance.

public class Toolbox {
  /**
   * Determines the overall distance between the points in the list
   */
  public static <T extends Vec<T>> double getAllDistances(List<T> points) {
     T prevPoint = points.get(0);
     T point;
     double sum = 0.0;
     int len = points.size();
     for (int i=1;i<len; i++) {
        point = points.get(i);
        sum+=point.distance(prevPoint);
        prevPoint = point;
     }
     return sum;
  }
}

This method is type-safe and works with all types implementing the generic Vec interface due to the <T extends Vec<T>> declaration. That way algorithms on vectors can safely be defined once for several variations of the classes.

In contrast, a declaration like below seems more natural at first, but does not work:

 public static <T> double getAllDistances(List<Vec<T>> points) {
    Vec<T> prevPoint = points.get(0);
    Vec<T> point;
    double sum = 0.0;
    for (int i=1; i<points.size(); i++) {
       point = points.get(i);
       sum+=point.distance(prevPoint);
       prevPoint = point;
    }
    return sum;
 }

Here, calling the method point.distance(prevPoint) gives a compiler error since prevPoint is of type Vec<T> but the method signature is distance(V other) and expects it to be T, rather than Vec<T>.