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