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 <methods>; }</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).
In the original
BootstrapMethods
attributeboth entries point to different target methods. You see clearly
#143 invokevirtual … RoleDTO.getName
and#155 invokevirtual … NameDescriptionDTO.getName
; these two arguments correspond to theimplMethod
parameter of the bootstrap methodmetafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType)
In contrast, in the obfuscated class’
BootstrapMethods
attributeboth 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 methodRoleDTO.getName
which has the functional signature(RoleDTO)String
andPermissionDTO
can’t be assigned toRoleDTO
(that’s exactly what the message says).