Java8 方法引用的 Proguard 混淆在运行时中断

Proguard obfuscation of Java8 method references breaks at runtime

我在混淆 java8 源代码时遇到了一个持续存在的问题。当 Lambda 方法引用在函数中多次使用时,它们似乎在运行时失败。 失败代码:

Set<String> roleNames = this.userDAO.getUserRoles(userDTO.getId()).stream().map(RoleDTO::getName).collect(Collectors.toSet());
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(roleNames);

Set<String> permissions = this.userDAO.getUserPermissions(userDTO.getId()).stream().map(NameDescriptionDTO::getName).collect(Collectors.toSet());
authorizationInfo.addStringPermissions(permissions);

这在使用 Maven 和 java 8.0_40 编译时工作正常,但是当混淆器使用以下堆栈跟踪混淆了 lib 时,这失败了:

org.jboss.weld.interceptor.proxy.InterceptorException: java.lang.BootstrapMethodError: call site initialization exception
~
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class package.db.dto.PermissionDTO; not a subtype of implementation type class package.db.dto.RoleDTO 
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233) ~[?:1.8.0_40]
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303) ~[?:1.8.0_40]
at java.lang.invoke.CallSite.makeSite(CallSite.java:302) ~[?:1.8.0_40]
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307) ~[?:1.8.0_40]
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297) ~[?:1.8.0_40]
at package.method(Unknown Source) ~[LIB.jar:?]

proguard-maven-plugin 设置:

<options>
    <option>-dontshrink</option>
    <option>-dontoptimize</option>
    <option>-keepdirectories</option>
    <option>-keepattributes Signature</option>
    <option>-keepattributes *Annotation*</option>
    <option>-keep public class * implements Foo</option>
    <option>-keepclassmembers,allowshrinking,allowobfuscation class * { synthetic &lt;methods&gt;; }</option>
</options>

重写代码以使用 lambda 表达式而不是方法引用格式似乎确实有效,但由于我在整个源代码的许多地方使用方法引用,这只是最后的解决方案:

Set<String> roleNames = this.userDAO.getRoles(userDTO.getId()).stream().map(r -> r.getName()).collect(Collectors.toSet());   
Set<String> permissions = this.userDAO.getPermissions(userDTO.getId()).stream().map(p -> p.getName()).collect(Collectors.toSet());

我调查了错误消息,似乎存在可能相关的 JVM 错误 (LambdaConversionException with generics: JVM bug?)。 使用 cfr_0_98 反编译混淆和未混淆的 java 文件没有显示出任何明显的差异: 混淆输出:

Set set = this.userDAO.a(userDTO.getId()).stream().map((Function<package.db.dto.RoleDTO, String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)Ljava/lang/Object;, getName(), (package/db/dto/RoleDTO;)Ljava/lang/String;)()).collect(Collectors.toSet());
Set set2 = this.userDAO.c(userDTO.getId()).stream().map((Function<package.db.dto.PermissionDTO, String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)Ljava/lang/Object;, getName(), (Lpackage /db/dto/PermissionDTO;)Ljava/lang/String;)()).collect(Collectors.toSet());

未混淆的输出(来自其他机器现在更具可读性并且也显示了问题。RoleDTO 被错误地使用了 2 次!):

Set set = this.userDAO.a(userDTO.getId()).stream().map(RoleDTO::getName).collect(Collectors.toSet());
Set set2 = this.userDAO.c(userDTO.getId()).stream().map(RoleDTO::getName).collect(Collectors.toSet());

任何关于 Proguard 标志可能对我们有帮助的指示都将不胜感激。

编辑:

这是反汇编的混淆字节码 (javap -v):

  Last modified 20-mrt-2015; size 3949 bytes
  MD5 checksum 1d3582e145d46fc813957931629413ff
public class package.web.security.impl.DefaultSecurityRealm extends org.apache.shiro.realm.AuthorizingRealm
  BootstrapMethods:
    0: #63 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #93 (Ljava/lang/Object;)Ljava/lang/Object;
        #62 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
        #95 (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
    1: #63 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #93 (Ljava/lang/Object;)Ljava/lang/Object;
        #62 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
        #94 (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
    #1 = String             #132          //  Some String
    #2 = String             #135          //  Some String
    #3 = String             #137          //  Some String
    #4 = Class              #156          //  java/lang/Object
    #5 = Class              #157          //  java/lang/String
    #6 = Class              #158          //  java/lang/invoke/LambdaMetafactory
    #7 = Class              #159          //  java/util/List
    #8 = Class              #160          //  java/util/Set
    #9 = Class              #161          //  java/util/stream/Collectors
   #10 = Class              #162          //  java/util/stream/Stream
   #11 = Class              #165          //  package/db/K
   #12 = Class              #166          //  package/db/dto/NameDescriptionDTO
   #13 = Class              #167          //  package/db/dto/RoleDTO
   #14 = Class              #168          //  package/db/dto/UserDTO
   #15 = Class              #169          //  package/web/security/impl/DefaultSecurityRealm
   #16 = Class              #170          //  org/apache/commons/lang/StringUtils
   #17 = Class              #171          //  org/apache/shiro/authc/AccountException
   #18 = Class              #172          //  org/apache/shiro/authc/AuthenticationException
   #19 = Class              #173          //  org/apache/shiro/authc/AuthenticationToken
   #20 = Class              #174          //  org/apache/shiro/authc/SimpleAuthenticationInfo
   #21 = Class              #175          //  org/apache/shiro/authc/UnknownAccountException
   #22 = Class              #176          //  org/apache/shiro/authc/UsernamePasswordToken
   #23 = Class              #177          //  org/apache/shiro/authz/SimpleAuthorizationInfo
   #24 = Class              #178          //  org/apache/shiro/codec/Base64
   #25 = Class              #179          //  org/apache/shiro/realm/AuthorizingRealm
   #26 = Class              #180          //  org/apache/shiro/subject/PrincipalCollection
   #27 = Class              #181          //  org/apache/shiro/util/SimpleByteSource
   #28 = Class              #182          //  org/jooq/exception/DataAccessException
   #29 = Fieldref           #15.#92       //  package/web/security/impl/DefaultSecurityRealm.userDAO:Lpackage/db/K;
   #30 = Methodref          #5.#78        //  java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
   #31 = Methodref          #6.#89        //  java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
   #32 = Methodref          #9.#91        //  java/util/stream/Collectors.toSet:()Ljava/util/stream/Collector;
   #33 = Methodref          #12.#80       //  package/db/dto/NameDescriptionDTO.getName:()Ljava/lang/String;
   #34 = Methodref          #13.#80       //  package/db/dto/RoleDTO.getName:()Ljava/lang/String;
   #35 = Methodref          #14.#79       //  package/db/dto/UserDTO.getId:()Ljava/util/UUID;
   #36 = Methodref          #14.#81       //  package/db/dto/UserDTO.getPassword:()Ljava/lang/String;
   #37 = Methodref          #14.#83       //  package/db/dto/UserDTO.getSalt:()Ljava/lang/String;
   #38 = Methodref          #15.#76       //  package/web/security/impl/DefaultSecurityRealm.createSimpleAuthenticationInfo:(Ljava/lang/String;)Lorg/apache/shiro/authc/SimpleAuthenticationInfo;
   #39 = Methodref          #15.#80       //  package/web/security/impl/DefaultSecurityRealm.getName:()Ljava/lang/String;
   #40 = Methodref          #15.#85       //  package/web/security/impl/DefaultSecurityRealm.getUsername:(Lorg/apache/shiro/authc/UsernamePasswordToken;)Ljava/lang/String;
   #41 = Methodref          #16.#86       //  org/apache/commons/lang/StringUtils.isBlank:(Ljava/lang/String;)Z
   #42 = Methodref          #16.#87       //  org/apache/commons/lang/StringUtils.isNotBlank:(Ljava/lang/String;)Z
   #43 = Methodref          #17.#66       //  org/apache/shiro/authc/AccountException."<init>":(Ljava/lang/String;)V
   #44 = Methodref          #18.#67       //  org/apache/shiro/authc/AuthenticationException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
   #45 = Methodref          #20.#65       //  org/apache/shiro/authc/SimpleAuthenticationInfo."<init>":(Ljava/lang/Object;Ljava/lang/Object;Lorg/apache/shiro/util/ByteSource;Ljava/lang/String;)V
   #46 = Methodref          #21.#66       //  org/apache/shiro/authc/UnknownAccountException."<init>":(Ljava/lang/String;)V
   #47 = Methodref          #22.#84       //  org/apache/shiro/authc/UsernamePasswordToken.getUsername:()Ljava/lang/String;
   #48 = Methodref          #23.#68       //  org/apache/shiro/authz/SimpleAuthorizationInfo."<init>":(Ljava/util/Set;)V
   #49 = Methodref          #23.#72       //  org/apache/shiro/authz/SimpleAuthorizationInfo.addStringPermissions:(Ljava/util/Collection;)V
   #50 = Methodref          #24.#77       //  org/apache/shiro/codec/Base64.decode:(Ljava/lang/String;)[B
   #51 = Methodref          #25.#64       //  org/apache/shiro/realm/AuthorizingRealm."<init>":()V
   #52 = Methodref          #27.#69       //  org/apache/shiro/util/SimpleByteSource."<init>":([B)V
   #53 = InterfaceMethodref #7.#90        //  java/util/List.stream:()Ljava/util/stream/Stream;
   #54 = InterfaceMethodref #10.#75       //  java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
   #55 = InterfaceMethodref #10.#88       //  java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
   #56 = InterfaceMethodref #11.#70       //  package/db/K.a:(Ljava/lang/String;)Lpackage/db/dto/UserDTO;
   #57 = InterfaceMethodref #11.#71       //  package/db/K.a:(Ljava/util/UUID;)Ljava/util/List;
   #58 = InterfaceMethodref #11.#74       //  package/db/K.c:(Ljava/util/UUID;)Ljava/util/List;
   #59 = InterfaceMethodref #26.#82       //  org/apache/shiro/subject/PrincipalCollection.getPrimaryPrincipal:()Ljava/lang/Object;
   #60 = InvokeDynamic      #0:#73        //  #0:apply:()Ljava/util/function/Function;
   #61 = InvokeDynamic      #1:#73        //  #1:apply:()Ljava/util/function/Function;
   #62 = MethodHandle       #5:#34        //  invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
   #63 = MethodHandle       #6:#31        //  invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
   #64 = NameAndType        #125:#102     //  "<init>":()V
   #65 = NameAndType        #125:#104     //  "<init>":(Ljava/lang/Object;Ljava/lang/Object;Lorg/apache/shiro/util/ByteSource;Ljava/lang/String;)V
   #66 = NameAndType        #125:#107     //  "<init>":(Ljava/lang/String;)V
   #67 = NameAndType        #125:#110     //  "<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
   #68 = NameAndType        #125:#114     //  "<init>":(Ljava/util/Set;)V
   #69 = NameAndType        #125:#124     //  "<init>":([B)V
   #70 = NameAndType        #138:#105     //  a:(Ljava/lang/String;)Lpackage/db/dto/UserDTO;
   #71 = NameAndType        #138:#115     //  a:(Ljava/util/UUID;)Ljava/util/List;
   #72 = NameAndType        #139:#113     //  addStringPermissions:(Ljava/util/Collection;)V
   #73 = NameAndType        #140:#99      //  apply:()Ljava/util/function/Function;
   #74 = NameAndType        #141:#115     //  c:(Ljava/util/UUID;)Ljava/util/List;
   #75 = NameAndType        #142:#117     //  collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
   #76 = NameAndType        #143:#106     //  createSimpleAuthenticationInfo:(Ljava/lang/String;)Lorg/apache/shiro/authc/SimpleAuthenticationInfo;
   #77 = NameAndType        #144:#109     //  decode:(Ljava/lang/String;)[B
   #78 = NameAndType        #147:#111     //  format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
   #79 = NameAndType        #148:#98      //  getId:()Ljava/util/UUID;
   #80 = NameAndType        #149:#97      //  getName:()Ljava/lang/String;
   #81 = NameAndType        #150:#97      //  getPassword:()Ljava/lang/String;
   #82 = NameAndType        #151:#96      //  getPrimaryPrincipal:()Ljava/lang/Object;
   #83 = NameAndType        #152:#97      //  getSalt:()Ljava/lang/String;
   #84 = NameAndType        #153:#97      //  getUsername:()Ljava/lang/String;
   #85 = NameAndType        #153:#122     //  getUsername:(Lorg/apache/shiro/authc/UsernamePasswordToken;)Ljava/lang/String;
   #86 = NameAndType        #154:#108     //  isBlank:(Ljava/lang/String;)Z
   #87 = NameAndType        #155:#108     //  isNotBlank:(Ljava/lang/String;)Z
   #88 = NameAndType        #163:#116     //  map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
   #89 = NameAndType        #164:#112     //  metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
   #90 = NameAndType        #184:#101     //  stream:()Ljava/util/stream/Stream;
   #91 = NameAndType        #185:#100     //  toSet:()Ljava/util/stream/Collector;
   #92 = NameAndType        #186:#134     //  userDAO:Lpackage/db/K;
   #93 = MethodType         #103          //  (Ljava/lang/Object;)Ljava/lang/Object;
   #94 = MethodType         #119          //  (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;
   #95 = MethodType         #120          //  (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
   #96 = Utf8               ()Ljava/lang/Object;
   #97 = Utf8               ()Ljava/lang/String;
   #98 = Utf8               ()Ljava/util/UUID;
   #99 = Utf8               ()Ljava/util/function/Function;
  #100 = Utf8               ()Ljava/util/stream/Collector;
  #101 = Utf8               ()Ljava/util/stream/Stream;
  #102 = Utf8               ()V
  #103 = Utf8               (Ljava/lang/Object;)Ljava/lang/Object;
  #104 = Utf8               (Ljava/lang/Object;Ljava/lang/Object;Lorg/apache/shiro/util/ByteSource;Ljava/lang/String;)V
  #105 = Utf8               (Ljava/lang/String;)Lpackage/db/dto/UserDTO;
  #106 = Utf8               (Ljava/lang/String;)Lorg/apache/shiro/authc/SimpleAuthenticationInfo;
  #107 = Utf8               (Ljava/lang/String;)V
  #108 = Utf8               (Ljava/lang/String;)Z
  #109 = Utf8               (Ljava/lang/String;)[B
  #110 = Utf8               (Ljava/lang/String;Ljava/lang/Throwable;)V
  #111 = Utf8               (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
  #112 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #113 = Utf8               (Ljava/util/Collection;)V
  #114 = Utf8               (Ljava/util/Set;)V
  #115 = Utf8               (Ljava/util/UUID;)Ljava/util/List;
  #116 = Utf8               (Ljava/util/function/Function;)Ljava/util/stream/Stream;
  #117 = Utf8               (Ljava/util/stream/Collector;)Ljava/lang/Object;
  #118 = Utf8               (Lpackage/db/K;)V
  #119 = Utf8               (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;
  #120 = Utf8               (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
  #121 = Utf8               (Lorg/apache/shiro/authc/AuthenticationToken;)Lorg/apache/shiro/authc/AuthenticationInfo;
  #122 = Utf8               (Lorg/apache/shiro/authc/UsernamePasswordToken;)Ljava/lang/String;
  #123 = Utf8               (Lorg/apache/shiro/subject/PrincipalCollection;)Lorg/apache/shiro/authz/AuthorizationInfo;
  #124 = Utf8               ([B)V
  #125 = Utf8               <init>
  #126 = Utf8               BootstrapMethods
  #127 = Utf8               Code
  #128 = Utf8               ConstantValue
  #129 = Utf8               EXCEPTION_ACCOUNT
  #130 = Utf8               EXCEPTION_AUTHENTICATION_DATASOURCE
  #131 = Utf8               EXCEPTION_UNKNOWN_ACCOUNT
  #132 = Utf8               Empty usernames are not allowed.
  #133 = Utf8               Ljava/lang/String;
  #134 = Utf8               Lpackage/db/K;
  #135 = Utf8               No account found for user [%s].
  #136 = Utf8               StackMapTable
  #137 = Utf8               There was a SQL error while authenticating user [%s].
  #138 = Utf8               a
  #139 = Utf8               addStringPermissions
  #140 = Utf8               apply
  #141 = Utf8               c
  #142 = Utf8               collect
  #143 = Utf8               createSimpleAuthenticationInfo
  #144 = Utf8               decode
  #145 = Utf8               doGetAuthenticationInfo
  #146 = Utf8               doGetAuthorizationInfo
  #147 = Utf8               format
  #148 = Utf8               getId
  #149 = Utf8               getName
  #150 = Utf8               getPassword
  #151 = Utf8               getPrimaryPrincipal
  #152 = Utf8               getSalt
  #153 = Utf8               getUsername
  #154 = Utf8               isBlank
  #155 = Utf8               isNotBlank
  #156 = Utf8               java/lang/Object
  #157 = Utf8               java/lang/String
  #158 = Utf8               java/lang/invoke/LambdaMetafactory
  #159 = Utf8               java/util/List
  #160 = Utf8               java/util/Set
  #161 = Utf8               java/util/stream/Collectors
  #162 = Utf8               java/util/stream/Stream
  #163 = Utf8               map
  #164 = Utf8               metafactory
  #165 = Utf8               package/db/K
  #166 = Utf8               package/db/dto/NameDescriptionDTO
  #167 = Utf8               package/db/dto/RoleDTO
  #168 = Utf8               package/db/dto/UserDTO
  #169 = Utf8               package/web/security/impl/DefaultSecurityRealm
  #170 = Utf8               org/apache/commons/lang/StringUtils
  #171 = Utf8               org/apache/shiro/authc/AccountException
  #172 = Utf8               org/apache/shiro/authc/AuthenticationException
  #173 = Utf8               org/apache/shiro/authc/AuthenticationToken
  #174 = Utf8               org/apache/shiro/authc/SimpleAuthenticationInfo
  #175 = Utf8               org/apache/shiro/authc/UnknownAccountException
  #176 = Utf8               org/apache/shiro/authc/UsernamePasswordToken
  #177 = Utf8               org/apache/shiro/authz/SimpleAuthorizationInfo
  #178 = Utf8               org/apache/shiro/codec/Base64
  #179 = Utf8               org/apache/shiro/realm/AuthorizingRealm
  #180 = Utf8               org/apache/shiro/subject/PrincipalCollection
  #181 = Utf8               org/apache/shiro/util/SimpleByteSource
  #182 = Utf8               org/jooq/exception/DataAccessException
  #183 = Utf8               setUserDAO
  #184 = Utf8               stream
  #185 = Utf8               toSet
  #186 = Utf8               userDAO
{
  protected org.apache.shiro.authz.AuthorizationInfo doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection);
    descriptor: (Lorg/apache/shiro/subject/PrincipalCollection;)Lorg/apache/shiro/authz/AuthorizationInfo;
    flags: ACC_PROTECTED
    Code:
      stack=3, locals=6, args_size=2
         0: aload_1       
         1: invokeinterface #59,  1           // InterfaceMethod org/apache/shiro/subject/PrincipalCollection.getPrimaryPrincipal:()Ljava/lang/Object;
         6: checkcast     #14                 // class package/db/dto/UserDTO
         9: astore_2      
        10: aload_0       
        11: getfield      #29                 // Field userDAO:Lpackage/db/K;
        14: aload_2       
        15: invokevirtual #35                 // Method package/db/dto/UserDTO.getId:()Ljava/util/UUID;
        18: invokeinterface #57,  2           // InterfaceMethod package/db/K.a:(Ljava/util/UUID;)Ljava/util/List;
        23: invokeinterface #53,  1           // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
        28: invokedynamic #60,  0             // InvokeDynamic #0:apply:()Ljava/util/function/Function;
        33: invokeinterface #55,  2           // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
        38: invokestatic  #32                 // Method java/util/stream/Collectors.toSet:()Ljava/util/stream/Collector;
        41: invokeinterface #54,  2           // InterfaceMethod java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
        46: checkcast     #8                  // class java/util/Set
        49: astore_3      
        50: new           #23                 // class org/apache/shiro/authz/SimpleAuthorizationInfo
        53: dup           
        54: aload_3       
        55: invokespecial #48                 // Method org/apache/shiro/authz/SimpleAuthorizationInfo."<init>":(Ljava/util/Set;)V
        58: astore        4
        60: aload_0       
        61: getfield      #29                 // Field userDAO:Lpackage/db/K;
        64: aload_2       
        65: invokevirtual #35                 // Method package/db/dto/UserDTO.getId:()Ljava/util/UUID;
        68: invokeinterface #58,  2           // InterfaceMethod package/db/K.c:(Ljava/util/UUID;)Ljava/util/List;
        73: invokeinterface #53,  1           // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
        78: invokedynamic #61,  0             // InvokeDynamic #1:apply:()Ljava/util/function/Function;
        83: invokeinterface #55,  2           // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
        88: invokestatic  #32                 // Method java/util/stream/Collectors.toSet:()Ljava/util/stream/Collector;
        91: invokeinterface #54,  2           // InterfaceMethod java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
        96: checkcast     #8                  // class java/util/Set
        99: astore        5
       101: aload         4
       103: aload         5
       105: invokevirtual #49                 // Method org/apache/shiro/authz/SimpleAuthorizationInfo.addStringPermissions:(Ljava/util/Collection;)V
       108: aload         4
       110: areturn       
}

更新

我们已经转移到 http://www.zelix.com/klassmaster/ 进行混淆。商业,但它确实适用于所有 Java 8 功能。 (我不隶属于)。

在原来的BootstrapMethods属性中

BootstrapMethods:
    0: #141 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #142 (Ljava/lang/Object;)Ljava/lang/Object;
        #143 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
        #144 (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
    1: #141 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #142 (Ljava/lang/Object;)Ljava/lang/Object;
        #155 invokevirtual package/db/dto/NameDescriptionDTO.getName:()Ljava/lang/String;
        #156 (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;

两个条目指向不同的目标方法。你看清楚#143 invokevirtual … RoleDTO.getName#155 invokevirtual … NameDescriptionDTO.getName;这两个参数对应于bootstrap方法的implMethod参数

metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType)

相比之下,在混淆后的 class' BootstrapMethods 属性中

  BootstrapMethods:
    0: #63 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #93 (Ljava/lang/Object;)Ljava/lang/Object;
        #62 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
        #95 (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
    1: #63 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
      Method arguments:
        #93 (Ljava/lang/Object;)Ljava/lang/Object;
        #62 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
        #94 (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;

两个条目引用完全相同的目标方法#62 invokevirtual … RoleDTO.getName

所以混淆器在这里进行了语义变化转换,我猜这是Proguard中的一个错误。 JRE 拒绝调用是正确的,因为最后一个条目仍然请求功能签名 (PermissionDTO)String 但希望 link 将其发送到具有功能签名 (RoleDTO)String 的目标方法 RoleDTO.getName并且 PermissionDTO 不能分配给 RoleDTO(这正是消息所说的)。