Mixins with Java

By Gerald Mücke | September 18, 2015

Mixins with Java

Mixins refer to additional functionality that can be added to a class. They are a special form of multiple inheritance, where properties or behaviors are inherited from several “parents.”

Mixins can solve two problem areas:

  • One wants to offer many optional features for a class.
  • One wants to offer a specific feature for many different classes. With the help of mixins, domain models can be kept simple by defining only the essential properties and optional properties can be added via mixins. External libraries can also be extended in this way without relying on dedicated extension points. Furthermore, cross-cutting functions can be realized via mixins, so that they do not have to be part of the type hierarchy and thus the domain model. They therefore provide an alternative to aspect-oriented programming. In Java, mixins have been supported since version 8 in the form of default methods on interfaces. Thus, functions can be added to a class by implementing an interface with default methods.
public interface MyMixin {
  default String helloWorld() {
    return "Hello World";
  }
}
 
public class MixinClass extends OtherClass implements MyMixin{
}
 
System.out.println(new MixinClass().helloWorld());

As an example case, consider a Swing application. Unlike JavaFX, Swing classes and methods are not designed for functional programming. In particular, event handlers must still be laboriously implemented and cannot be defined via lambda expressions. With the help of mixins, it is possible to create the ability to pass functions of the event handler to a method defined in the mixin interface as a lambda expression, i.e., as a FunctionalInterface. The mixin itself defines a method that is already implemented by the object to be extended. The default method receives the instance of the FunctionalInterface and wraps it in an event handler that is passed to the method defined in the interface and already implemented.

public interface FocusEventProducerMixin {
  void addFocusListener(FocusListener l); //Methode des Objekts
 
  default void addFocusGainedListener(Consumer<FocusEvent> c) {
    addFocusListener(new FocusAdapter(){
      public void focusGained(FocusEvent e) {
        c.accept(e);
      }
    });
  }
}

The Swing class (or any other 3rd-party class) is then extended by a subtype that implements the mixin interface.

public class JButtonLambda
  extends JButton
  implements FocusEventProducerMixin{
}

Finally, the new class is instantiated, and the event handler function is passed as a lambda expression:

JButtonLambda jbutton = ...
jbutton.addFocusGainedListener(e -> System.out.println(e));
comments powered by Disqus