11

I'm using org.apache.commons.lang3.BooleanUtils in the commons-lang3 (version 3.1). When I try to compile next line of code

BooleanUtils.xor(true, true);

using maven-compiler-plugin (version 3.3), I'm getting a compilation failure message:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.3:compile (default-compile) on project exchange: Compilation failure
[ERROR] MyClass.java:[33,34] reference to xor is ambiguous, both method xor(boolean...) in org.apache.commons.lang3.BooleanUtils and method xor(java.lang.Boolean...) in org.apache.commons.lang3.BooleanUtils match

I use Java 1.7.0_55 to compile.

How can I solve this?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Deplake
  • 865
  • 2
  • 9
  • 22

3 Answers3

8

The problem happens because the signature of the method has variable arguments. When a method is invoked, there are 3 phases during which all applicable methods are searched. Methods with variable arguments are searched in phase 3 where boxing, and unboxing is also allowed.

So both xor(boolean...) and xor(Boolean...) are applicable here because boxing is taken into account. When multiple methods are applicable, only the most specific is invoked. But in this case, boolean and Boolean can't be compared, so there is no more specific method, hence the compiler error: both methods match.

A workaround is to create an explicit array:

public static void main(String[] args) {
    xor(new boolean[] { true, false }); // will call the primitive xor
    xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }); // will call the non-primitive xor
}

private static Boolean xor(Boolean... booleans) {
    System.out.println("Boolean...");
    return Boolean.TRUE;
}

private static boolean xor(boolean... booleans) {
    System.out.println("boolean...");
    return true;
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 5
    This works, but for me looks like really bad code :) I was surprized that this can happen in the apcahe-commons-lengs3 – Deplake Nov 25 '15 at 15:06
0

Funny : a corner case where autoboxing go straight in your way.

The simplest way to fix that is to write

BooleanUtils.xor((boolean) true, (boolean) true)
Riduidel
  • 22,052
  • 14
  • 85
  • 185
0

You can just rip out the method you want and put it in your own util class. Just don't copy both or you'll be back to square one.

public final class MyUtils {
    /**
     * @see BooleanUtils#xor(boolean...)
     */
    public static boolean xor(final boolean... array) {
        // Validates input
        if (array == null) {
            throw new IllegalArgumentException("The Array must not be null");
        }
        if (array.length == 0) {
            throw new IllegalArgumentException("Array is empty");
        }

        // false if the neutral element of the xor operator
        boolean result = false;
        for (final boolean element : array) {
            result ^= element;
        }

        return result;
    }
}
ScrappyDev
  • 2,307
  • 8
  • 40
  • 60