Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Google Guava's ArrayListMultimap clear method throw IllegalAccessError when called by method reference?

Sample code to demonstrate the failure:

package ia.quant.nextgen.entry;

import com.google.common.collect.ArrayListMultimap;

import java.util.function.Consumer;

/**
 * Created by arpeke on 2015-12-18.
 */
public final class SampleMain {

    public static void main(String[] argArr) {

        final ArrayListMultimap<Void, Void> arrayListMultimap = ArrayListMultimap.create();
        arrayListMultimap.clear();

        final Consumer<ArrayListMultimap> arrayListMultimapConsumer = ArrayListMultimap::clear;
        arrayListMultimapConsumer.accept(arrayListMultimap);
    }
}

Here is the Error (not Exception) I see:

Exception in thread "main" java.lang.IllegalAccessError:
    tried to access class com.google.common.collect.AbstractMapBasedMultimap
    from class ia.quant.nextgen.entry.SampleMain
at ia.quant.nextgen.entry.SampleMain.lambda$main$1(SampleMain.java:17)
at ia.quant.nextgen.entry.SampleMain.main(SampleMain.java:18)

I am using 32-bit Java 8 (v1.8.0_60) with Google Guava v19.0. My Google-Fu tells me Google Guice is the root cause, but lacks credible explanation. (This is part of a much larger project that also includes Google Guice v3.0 via Apache Maven.)

Sample ref: https://github.com/hierynomus/scannit/issues/7

Does anyone know...?

  1. The root cause
  2. A workaround

(Finally, I also tried Google Guava v18.0, but no luck.)

Update

This code works, but I don't understand why. (Do I misunderstand non-static method references?)

final Consumer<ArrayListMultimap> arrayListMultimapConsumer = x -> x.clear();
arrayListMultimapConsumer.accept(arrayListMultimap);
like image 465
kevinarpe Avatar asked Dec 26 '15 15:12

kevinarpe


1 Answers

Lambdas need to find the last definition of a method. So when you write ArrayListMultimap::clear, the interpreter actually tries to find what class of the hierarchy last defined the method clear. It happens that the method is last defined in AbstractMapBasedMultimap, which is a package-private class.

The issue at hand is more than likely in the JRE, but two workarounds exist.

The first one is the one that you described. The second would be that the Guava team either makes AbstractMapBasedMultimap public or redefines the clear() method in ArrayListMultimap (and that method would only need to call super.clear()).

The easiest of the two workaround for you at this moment is the one you tried. If I were you, I would still ask the Guava team to make their own workaround so that it doesn't impact more users.

Regarding your workaround, it works because you use the method instead of referring to it.

like image 126
Olivier Grégoire Avatar answered Nov 13 '22 13:11

Olivier Grégoire