使用 Java 8 流时的 Aspectj BootstrapMethodError API
Aspectj BootstrapMethodError when using Java 8 stream API
所以我在这里 - 运行 一个 spring 应用程序 spring roo 落后。
我过去常常将我的控制器分成多个方面,所以我的主控制器看起来像这样:
@Controller
@RequestMapping("/apples")
@SessionAttributes(types = {Apple.class})
public class AppleController {
}
其他方面扩展了它的功能,例如:
privileged aspect AppleController_Basics {
@RequestMapping(value = "/allApples", produces = "text/html", method=RequestMethod.GET)
public String AppleController.allApples(Model model) {
...
return "apples/list";
}
}
现在,当我尝试在以下方面使用 Java 8 流 API 时:
apples.stream().filter(a -> a.isSweet()).collect(Collectors.toList());
我遇到以下异常:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.BootstrapMethodError: java.lang.NoSuchMethodError: com.apple.web.AppleController.lambda[=15=](Lcom/apple/model/Apple;)Z
当我将流 API 用于另一个实体而不是 Apple 本身时,我得到一个稍微不同的异常:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method com.apple.web.AppleController.lambda[=16=](Lcom/apple/security/AppleEater;)Z from class com.apple.web.aspects.AppleController_Basics
使用 forEach 时出现 OutOfMemoryError::
apples.forEach(System.out::println);
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
当我在主要 class 中使用这些表达式时,一切正常。
插件看起来像这样:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.10</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<complianceLevel>1.8</complianceLevel>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<weaveWithAspectsInMainSourceFolder>false</weaveWithAspectsInMainSourceFolder>
</configuration>
</plugin>
我尝试了不同的方法来更改我的 aspectj 插件配置以使其工作 - 但没有成功。感谢任何提示或帮助,因为我现在真的很困惑,请不要讨厌 <3
javap -c -p AppleController.class
public java.lang.String allApples(org.springframework.ui.Model);
Code:
0: aload_0
1: aload_1
2: invokestatic #528 // Method com/apple/web/aspects/AppleController_Basics.ajc$interMethod$com_apple_web_aspects_AppleController_Basics$com_apple_web_AppleController$allApples:(Lcom/apple/web/AppleController;Lorg/springframework/ui/Model;)Ljava/lang/String;
5: areturn
现在那个方法:
lambda[=10=](Lcom/apple/model/Apple;)Z
实际上是你的 lambda a -> a.isSweet()
的脱糖,它看起来像这样:
private static boolean lambda[=11=](Apple s){
return s.isSweet();
}
此方法由编译器生成。除非你使用一些奇怪的编译器,否则这一定是 aspectj 中的一个错误。
您可以通过调用反编译您的 .class 文件的命令来检查 AppleController
中是否存在该方法:
javap -c -p AppleController.class
输出应该是这样的:
private static boolean lambda[=13=](com.model.apple.Apple);
Code:
0: aload_0
1: invokevirtual #9 // Method isSweet:()Z
4: ireturn
如果这个方法确实存在(javac正确完成了他的工作),理论上你无法获得java.lang.NoSuchMethodError
,这意味着
aspectj 在您使用的版本中做了一些非常有趣的事情。
我非常怀疑最后一段,但以防万一...
另一方面,如果你反编译(javap 命令)并且你没有看到 lambda[=17=]
方法,而是一个名为 lambda$main[=18=]
的方法,这意味着你正在使用 jdk-9 进行编译或一些不明显的 Eclipse 编译器。
这显然是 AspectJ 编译器的错误或缺陷。我为它创建了一个bug ticket。
这是我从您的代码中提取的(非Spring)测试用例:
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());
}
}
控制台日志如下所示:
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[=13=](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[=13=](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
在上面的方面,您还可以看到一个临时解决方法:使用方法引用或经典匿名子类而不是 lambda。
背景信息:AspectJ 编译器 AJC 是 Eclipse Java 编译器 ECJ 的一个定期更新的分支(顺便说一句,AspectJ 也是一个官方 Eclipse 项目)。所以这个错误可能在 ECJ 中,但可能在 AJC 中。
所以我在这里 - 运行 一个 spring 应用程序 spring roo 落后。
我过去常常将我的控制器分成多个方面,所以我的主控制器看起来像这样:
@Controller
@RequestMapping("/apples")
@SessionAttributes(types = {Apple.class})
public class AppleController {
}
其他方面扩展了它的功能,例如:
privileged aspect AppleController_Basics {
@RequestMapping(value = "/allApples", produces = "text/html", method=RequestMethod.GET)
public String AppleController.allApples(Model model) {
...
return "apples/list";
}
}
现在,当我尝试在以下方面使用 Java 8 流 API 时:
apples.stream().filter(a -> a.isSweet()).collect(Collectors.toList());
我遇到以下异常:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.BootstrapMethodError: java.lang.NoSuchMethodError: com.apple.web.AppleController.lambda[=15=](Lcom/apple/model/Apple;)Z
当我将流 API 用于另一个实体而不是 Apple 本身时,我得到一个稍微不同的异常:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method com.apple.web.AppleController.lambda[=16=](Lcom/apple/security/AppleEater;)Z from class com.apple.web.aspects.AppleController_Basics
使用 forEach 时出现 OutOfMemoryError::
apples.forEach(System.out::println);
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
当我在主要 class 中使用这些表达式时,一切正常。
插件看起来像这样:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.10</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<complianceLevel>1.8</complianceLevel>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<weaveWithAspectsInMainSourceFolder>false</weaveWithAspectsInMainSourceFolder>
</configuration>
</plugin>
我尝试了不同的方法来更改我的 aspectj 插件配置以使其工作 - 但没有成功。感谢任何提示或帮助,因为我现在真的很困惑,请不要讨厌 <3
javap -c -p AppleController.class
public java.lang.String allApples(org.springframework.ui.Model);
Code:
0: aload_0
1: aload_1
2: invokestatic #528 // Method com/apple/web/aspects/AppleController_Basics.ajc$interMethod$com_apple_web_aspects_AppleController_Basics$com_apple_web_AppleController$allApples:(Lcom/apple/web/AppleController;Lorg/springframework/ui/Model;)Ljava/lang/String;
5: areturn
现在那个方法:
lambda[=10=](Lcom/apple/model/Apple;)Z
实际上是你的 lambda a -> a.isSweet()
的脱糖,它看起来像这样:
private static boolean lambda[=11=](Apple s){
return s.isSweet();
}
此方法由编译器生成。除非你使用一些奇怪的编译器,否则这一定是 aspectj 中的一个错误。
您可以通过调用反编译您的 .class 文件的命令来检查 AppleController
中是否存在该方法:
javap -c -p AppleController.class
输出应该是这样的:
private static boolean lambda[=13=](com.model.apple.Apple);
Code:
0: aload_0
1: invokevirtual #9 // Method isSweet:()Z
4: ireturn
如果这个方法确实存在(javac正确完成了他的工作),理论上你无法获得java.lang.NoSuchMethodError
,这意味着
aspectj 在您使用的版本中做了一些非常有趣的事情。
我非常怀疑最后一段,但以防万一...
另一方面,如果你反编译(javap 命令)并且你没有看到 lambda[=17=]
方法,而是一个名为 lambda$main[=18=]
的方法,这意味着你正在使用 jdk-9 进行编译或一些不明显的 Eclipse 编译器。
这显然是 AspectJ 编译器的错误或缺陷。我为它创建了一个bug ticket。
这是我从您的代码中提取的(非Spring)测试用例:
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());
}
}
控制台日志如下所示:
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[=13=](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[=13=](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
在上面的方面,您还可以看到一个临时解决方法:使用方法引用或经典匿名子类而不是 lambda。
背景信息:AspectJ 编译器 AJC 是 Eclipse Java 编译器 ECJ 的一个定期更新的分支(顺便说一句,AspectJ 也是一个官方 Eclipse 项目)。所以这个错误可能在 ECJ 中,但可能在 AJC 中。