Proguard obfuscation of Java8 method references br

2019-05-17 20:10发布

I am encountering a persistent problem when obfuscating java8 source code. Lambda method references seem to fail at runtime when they are used multiple times within a function. The failing code:

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);

This works fine when compiling with maven and java 8.0_40, however this fails when proguard has obfuscated the lib with the following stack trace:

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 settings:

<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>

Rewriting the code to use a lambda expression instead of the method reference format does seem to work, but as I use method references in numerous places throughout the source, this would only be a last resort solution:

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());

I investigated the error message and it seems that there is JVM bug (LambdaConversionException with generics: JVM bug?) which might be related. Using cfr_0_98 to decompile the obfuscated and unobfuscated java files does not show any obvious differences: Obfuscated output:

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());

Unobfuscated output (from other machine now more readable and also showing the problem. RoleDTO is incorrectly being used 2 times!):

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());

Any pointers would be very much appreciated on which Proguard flags might help us out.

Edit:

Here is the obfuscated bytecode disassembled (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       
}

Update

We have moved to http://www.zelix.com/klassmaster/ for our obfuscation. Commercial, but it does work well with all Java 8 features. (I am not affiliated).

1条回答
相关推荐>>
2楼-- · 2019-05-17 20:39

In the original BootstrapMethods attribute

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;

both entries point to different target methods. You see clearly #143 invokevirtual … RoleDTO.getName and #155 invokevirtual … NameDescriptionDTO.getName; these two arguments correspond to the implMethod parameter of the bootstrap method

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

In contrast, in the obfuscated class’ BootstrapMethods attribute

  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;

both entries refer to exactly the same target method #62 invokevirtual … RoleDTO.getName.

So the obfuscator made a semantic changing transformation here, I guess it’s a bug in Proguard. The JRE is correct in rejecting the call as the last entry still requests the functional signature (PermissionDTO)String but wants to link it to the target method RoleDTO.getName which has the functional signature (RoleDTO)String and PermissionDTO can’t be assigned to RoleDTO (that’s exactly what the message says).

查看更多
登录 后发表回答