javagradlecompilationdefault-method

Java ignores default interface methods in an imported library and treats them as abstract


I am trying to use the Functional Java library.

I just include it in build.gradle with

dependencies {
    compile "org.functionaljava:functionaljava:4.8.1"
}

and compile using openjdk-15 and it just works... mostly.

The problem I have is the following:

I need to implement an interface (fj.Ord.Definition), which should be a functional interface - it has one non-default method and many default methods.

That means that an implementation via a lambda, or this

new Ord.Definition<MyClass>() {
    @Override
    public F<MyClass, Ordering> compare(MyClass a) {
        return b -> a.myCompare(b);
    }
}

should be fine.

What I get instead is:

Intellij: "Class 'Anonymous class derived from Definition' must either be declared abstract or implement abstract method 'compare(A, A)' in 'Definition'"

If I try to compile it anyway, javac: error: <anonymous MyClass$1> is not abstract and does not override abstract method ord()

This of course non only for the ord, but for the other 11 default methods as well.

If I try to implement them with Ord.Definition.super as in

@Override
public F<A, A> prepend(A a1) {
    return Ord.Definition.super(a1);
}

I get the error 'java.lang.Object' is not an inner class.

To note here is that the functionaljava library source code is full of these kinds of error (and many more) when viewed from Intellij in my project. Errors where Intellij complains about various mismatches between type variables and Object are also common there.

So my questions are:

  1. How can I implement Ord.Definition as a lambda, as the library intends (or at least by using its default methods)?
  2. What allows that library to be compiled despite how many apparent errors it contains?

EDIT1: Per request, here are some chunks of the referenced fj.Ord.Definition interface:

/**
 * Tests for ordering between two objects.
 *
 * @version %build.number%
 */
public final class Ord<A> {

  /**
   * Primitives functions of Ord: minimal definition and overridable methods.
   */
  public interface Definition<A> extends Equal.Definition<A>, Semigroup.Definition<A> {

    F<A, Ordering> compare(A a);

    default Ordering compare(A a1, A a2) {
      return compare(a1).f(a2);
    }

    // equal:
    @Override
    default boolean equal(A a1, A a2) {
      return compare(a1, a2) == Ordering.EQ;
    }

...

    @Override
    default F<A, A> prepend(A a1) {
      return apply((a2, o) -> o == Ordering.GT ? a1 : a2, compare(a1));
    }

...

    /**
     * Build an ord instance from this definition.
     * to be called after some successive {@link #then(F, Ord)} calls.
     */
    default Ord<A> ord() {
      return ordDef(this);
    }
  }

...

EDIT2: It turns out, in this case I can sidestep the issue by creating my ordering with either the method fj.Ord#ord(fj.F<A,fj.F<A,fj.Ordering>>) or fj.Ord#ord(fj.F2<A,A,fj.Ordering>) which each produce an Ord<A>. That does however not answer the questions I posed.


Solution

  • You're using the wrong dependency. org.functionaljava:functionaljava is retrofitted to work on Java 7 (and 6 according to the project docs). You need to use org.functionaljava:functionaljava-java8 instead:

    dependencies {
        implementation "org.functionaljava:functionaljava-java8:4.8.1"
    }