Bug 513528 - Using lambda in ITD method causes IllegalAccessError
Summary: Using lambda in ITD method causes IllegalAccessError
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.8.10   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: 1.9.2   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-12 10:52 EDT by Alexander Kriegisch CLA
Modified: 2018-10-10 16:29 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Kriegisch CLA 2017-03-12 10:52:16 EDT
See http://stackoverflow.com/a/42747116/1082681.

-----------------------------------------------------------------------

package de.scrum_master.app;

public class Apple {
  private String type;
  private boolean sweet;

  public Apple(String type, boolean sweet) {
    this.type = type;
    this.sweet = sweet;
  }

  public String getType() {
    return type;
  }

  public boolean isSweet() {
    return sweet;
  }
}

-----------------------------------------------------------------------

package de.scrum_master.app;

import java.util.Arrays;
import java.util.List;

public class AppleController {
  private static final List<Apple> APPLES =
    Arrays.asList(new Apple("Granny Smith", false), new Apple("Golden Delicious", true));

  public static void main(String[] args) {
    AppleController appleController = new AppleController();
    System.out.println("Named: " + appleController.namedApples(APPLES, "Smith"));
    System.out.println("Sweet: " + appleController.sweetApples(APPLES));
    System.out.println("Sour:  " + appleController.sourApples(APPLES));
  }
}

-----------------------------------------------------------------------

package de.scrum_master.aspect;

import java.util.List;
import java.util.stream.Collectors;

import java.util.function.Predicate;
import de.scrum_master.app.Apple;
import de.scrum_master.app.AppleController;

public privileged aspect AppleControllerITDAspect {
  public List<Apple> AppleController.namedApples(List<Apple> apples, String subString) {
    // Anonymous subclass works
    return apples.stream().filter(new Predicate<Apple>() {
      @Override
      public boolean test(Apple a) {
        return a.getType().contains(subString);
      }
    }).collect(Collectors.toList());
  }

  public List<Apple> AppleController.sweetApples(List<Apple> apples) {
    // Method reference works
    return apples.stream().filter(Apple::isSweet).collect(Collectors.toList());
  }

  public List<Apple> AppleController.sourApples(List<Apple> apples) {
    // Lambda causes IllegalAccessError
    return apples.stream().filter(a -> !a.isSweet()).collect(Collectors.toList());
  }
}

-----------------------------------------------------------------------

Console log:

Named: [de.scrum_master.app.Apple@6f496d9f]
Sweet: [de.scrum_master.app.Apple@4e50df2e]
Exception in thread "main" java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method de.scrum_master.app.AppleController.lambda$0(Lde/scrum_master/app/Apple;)Z from class de.scrum_master.aspect.AppleControllerITDAspect
    at de.scrum_master.aspect.AppleControllerITDAspect.ajc$interMethod$de_scrum_master_aspect_AppleControllerITDAspect$de_scrum_master_app_AppleController$sourApples(AppleControllerITDAspect.aj:28)
    at de.scrum_master.app.AppleController.sourApples(AppleController.java:1)
    at de.scrum_master.aspect.AppleControllerITDAspect.ajc$interMethodDispatch1$de_scrum_master_aspect_AppleControllerITDAspect$de_scrum_master_app_AppleController$sourApples(AppleControllerITDAspect.aj)
    at de.scrum_master.app.AppleController.main(AppleController.java:14)
Caused by: java.lang.IllegalAccessError: tried to access method de.scrum_master.app.AppleController.lambda$0(Lde/scrum_master/app/Apple;)Z from class de.scrum_master.aspect.AppleControllerITDAspect
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(Unknown Source)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(Unknown Source)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(Unknown Source)
    at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(Unknown Source)
    at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(Unknown Source)
    ... 4 more

-----------------------------------------------------------------------

As I said on the mailing list, ere is some javap output:

  private static boolean lambda$0(de.scrum_master.app.Apple);
    Code:
       0: aload_0
       1: invokevirtual #90                 // Method
       de/scrum_master/app/Apple.isSweet:()Z
       4: ifeq          11
       7: iconst_0
       8: goto          12
      11: iconst_1
      12: ireturn

As you can see, the lambda is declared private. This is why the aspect's ITD method dispatcher cannot call it. So the solution would be to either declare the lambda within the aspect like the dispatcher or to make the lambda public.
Comment 1 Alexander Kriegisch CLA 2018-09-26 03:50:33 EDT
Andy, is this one still on your radar? I know you are busy with Java 11 and 1.9.2-RC. Anyway, ... ;-)
Comment 2 Andrew Clement CLA 2018-10-10 16:29:12 EDT
It wasn't until you added a comment ;)  Fixed up, lambda is private if looks to be used in an ITD. Thanks for the testcode, it passes now.