-
-
Notifications
You must be signed in to change notification settings - Fork 9k
修复 RsaCryptoUtil 无法加密继承字段和嵌套对象的问题 #3841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,196 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.github.binarywang.wxpay.v3.util; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReceiverV3Request; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.github.binarywang.wxpay.exception.WxPayException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.github.binarywang.wxpay.v3.SpecEncrypt; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.google.gson.annotations.SerializedName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.Data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.testng.annotations.Test; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.lang.reflect.Field; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.ArrayList; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static org.testng.Assert.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * RsaCryptoUtil 测试类 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class RsaCryptoUtilTest { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 测试反射能否找到嵌套类中的 @SpecEncrypt 注解字段 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testFindAnnotatedFieldsInNestedClass() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 创建 Receiver 对象 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProfitSharingV3Request.Receiver receiver = new ProfitSharingV3Request.Receiver(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setName("测试姓名"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 使用反射查找带有 @SpecEncrypt 注解的字段 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Class<?> receiverClass = receiver.getClass(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Field[] fields = receiverClass.getDeclaredFields(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("=== Receiver 类中的所有字段 ==="); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean foundNameField = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean nameFieldHasAnnotation = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Field field : fields) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("字段名: " + field.getName() + ", 类型: " + field.getType().getName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (field.getName().equals("name")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foundNameField = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (field.isAnnotationPresent(SpecEncrypt.class)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nameFieldHasAnnotation = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println(" -> name 字段有 @SpecEncrypt 注解"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println(" -> name 字段没有 @SpecEncrypt 注解"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+35
to
+50
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 验证能够找到 name 字段并且它有 @SpecEncrypt 注解 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue(foundNameField, "应该能找到 name 字段"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue(nameFieldHasAnnotation, "name 字段应该有 @SpecEncrypt 注解"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 测试嵌套对象中的字段加密 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 验证 List<Receiver> 中每个 Receiver 对象的 name 字段是否能被正确找到和处理 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testEncryptFieldsWithNestedObjects() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 创建测试对象 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProfitSharingV3Request request = ProfitSharingV3Request.newBuilder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .appid("test-appid") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .subMchId("test-submchid") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .transactionId("test-transaction") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .outOrderNo("test-order-no") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unfreezeUnsplit(true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<ProfitSharingV3Request.Receiver> receivers = new ArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProfitSharingV3Request.Receiver receiver = new ProfitSharingV3Request.Receiver(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setName("张三"); // 设置需要加密的字段 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setAccount("test-account"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setType("PERSONAL_OPENID"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setAmount(100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setRelationType("STORE"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receiver.setDescription("测试分账"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| receivers.add(receiver); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request.setReceivers(receivers); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 验证 receivers 字段有 @SpecEncrypt 注解 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Field receiversField = ProfitSharingV3Request.class.getDeclaredField("receivers"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean hasAnnotation = receiversField.isAnnotationPresent(SpecEncrypt.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("ProfitSharingV3Request.receivers 字段有 @SpecEncrypt 注解: " + hasAnnotation); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue(hasAnnotation, "receivers 字段应该有 @SpecEncrypt 注解"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (NoSuchFieldException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fail("应该能找到 receivers 字段"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("测试对象创建成功,name字段: " + receiver.getName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+88
to
+94
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 验证name字段不为null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertNotNull(receiver.getName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals(receiver.getName(), "张三"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+61
to
+98
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 测试单个对象中的字段加密 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 验证直接在对象上的 @SpecEncrypt 字段是否能被正确找到 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testEncryptFieldsWithDirectField() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 创建测试对象 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProfitSharingReceiverV3Request request = ProfitSharingReceiverV3Request.newBuilder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .appid("test-appid") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .subMchId("test-submchid") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .type("PERSONAL_OPENID") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .account("test-account") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .name("李四") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .relationType("STORE") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 验证 name 字段有 @SpecEncrypt 注解 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Field nameField = ProfitSharingReceiverV3Request.class.getDeclaredField("name"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean hasAnnotation = nameField.isAnnotationPresent(SpecEncrypt.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("ProfitSharingReceiverV3Request.name 字段有 @SpecEncrypt 注解: " + hasAnnotation); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue(hasAnnotation, "name 字段应该有 @SpecEncrypt 注解"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (NoSuchFieldException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fail("应该能找到 name 字段"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("测试对象创建成功,name字段: " + request.getName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+120
to
+126
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("ProfitSharingReceiverV3Request.name 字段有 @SpecEncrypt 注解: " + hasAnnotation); | |
| assertTrue(hasAnnotation, "name 字段应该有 @SpecEncrypt 注解"); | |
| } catch (NoSuchFieldException e) { | |
| fail("应该能找到 name 字段"); | |
| } | |
| System.out.println("测试对象创建成功,name字段: " + request.getName()); | |
| assertTrue(hasAnnotation, "name 字段应该有 @SpecEncrypt 注解"); | |
| } catch (NoSuchFieldException e) { | |
| fail("应该能找到 name 字段"); | |
| } | |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
测试方法 testEncryptFieldsWithDirectField 没有实际调用 RsaCryptoUtil.encryptFields() 方法来验证加密功能是否正常工作。此测试只验证了字段存在性和注解存在性,但没有测试核心的加密逻辑。建议添加实际的加密调用和验证,确保修复后的方法能够正确加密字段。
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method overrides ParentRequest.canEqual; it is advisable to add an Override annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
在测试代码中使用 System.out.println 进行调试输出不是最佳实践。建议移除这些调试输出语句,或者使用日志框架(如 SLF4J)进行日志记录。保留的调试输出会在测试运行时产生不必要的控制台输出。
| System.out.println("=== 测试继承场景 ==="); | |
| System.out.println("父类字段值: " + request.getParentName()); | |
| System.out.println("子类字段值: " + request.getChildName()); | |
| // 使用 getDeclaredFields 只能找到子类字段 | |
| Field[] childFields = ChildRequest.class.getDeclaredFields(); | |
| System.out.println("使用 getDeclaredFields 找到的字段数: " + childFields.length); | |
| // 使用 getAllFields 辅助方法应该能找到父类和子类的所有字段 | |
| List<Field> allFields = getAllFields(ChildRequest.class); | |
| System.out.println("使用 getAllFields 找到的字段数: " + allFields.size()); | |
| int annotatedFieldCount = 0; | |
| for (Field field : allFields) { | |
| if (field.isAnnotationPresent(SpecEncrypt.class)) { | |
| annotatedFieldCount++; | |
| System.out.println(" -> 找到带 @SpecEncrypt 注解的字段: " + field.getName()); | |
| // 使用 getDeclaredFields 只能找到子类字段 | |
| Field[] childFields = ChildRequest.class.getDeclaredFields(); | |
| // 使用 getAllFields 辅助方法应该能找到父类和子类的所有字段 | |
| List<Field> allFields = getAllFields(ChildRequest.class); | |
| int annotatedFieldCount = 0; | |
| for (Field field : allFields) { | |
| if (field.isAnnotationPresent(SpecEncrypt.class)) { | |
| annotatedFieldCount++; | |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
辅助方法 getAllFields 在测试类中重复实现了与生产代码中相同的逻辑。这会导致代码重复,如果将来需要修改这个逻辑,需要在两个地方同时修改。建议直接使用反射调用 RsaCryptoUtil 中的私有 getAllFields 方法,或者将该方法改为包级别可见性以便测试使用。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
在第52行,应该直接使用
Collections.addAll(fields, declaredFields)而不是使用完全限定名java.util.Collections.addAll(fields, declaredFields)。因为已经在第20行导入了java.util.Collections,使用完全限定名是多余的,不符合代码风格。