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 functi
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).