From 579c7f681a243440aeb8d02b10e68b4685ece666 Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Tue, 18 Aug 2026 12:48:24 +0800
Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E6=B6=88=E9=99=A4=E6=97=A7=E9=80=9A?=
=?UTF-8?q?=E7=9F=A5=E5=A4=B4=E7=A9=BA=E5=80=BC=E9=87=8D=E8=BD=BD=E6=AD=A7?=
=?UTF-8?q?=E4=B9=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../wxpay/bean/ecommerce/SignatureHeader.java | 2 +-
.../LegacyEcommerceApiCompatibilityTest.java | 19 +++++++++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
index 9bf268278..fe7eee99b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
@@ -18,7 +18,7 @@
@NoArgsConstructor
@AllArgsConstructor
@Deprecated
-public class SignatureHeader implements Serializable {
+public class SignatureHeader extends com.github.binarywang.wxpay.bean.notify.SignatureHeader implements Serializable {
private static final long serialVersionUID = -6958015499416059949L;
/**
* 时间戳
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
index a82dadb76..1b0e1302d 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
@@ -25,4 +25,23 @@ public void shouldKeepLegacyRefundAndWithdrawNotificationSignatures() throws Exc
Assert.assertNotNull(EcommerceService.class.getMethod("parseRefundNotifyResult", String.class, legacyHeader));
Assert.assertNotNull(EcommerceService.class.getMethod("parseWithdrawNotifyResult", String.class, legacyHeader));
}
+
+ @Test
+ public void shouldMakeLegacyHeaderMoreSpecificAndPreserveSignatureFields() {
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader legacyHeader =
+ new com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader();
+ legacyHeader.setTimeStamp("timestamp");
+ legacyHeader.setNonce("nonce");
+ legacyHeader.setSigned("signed");
+ legacyHeader.setSerialNo("serial-no");
+
+ Assert.assertTrue(com.github.binarywang.wxpay.bean.notify.SignatureHeader.class
+ .isAssignableFrom(legacyHeader.getClass()));
+ com.github.binarywang.wxpay.bean.notify.SignatureHeader unifiedHeader =
+ EcommerceService.toUnifiedSignatureHeader(legacyHeader);
+ Assert.assertEquals(unifiedHeader.getTimeStamp(), "timestamp");
+ Assert.assertEquals(unifiedHeader.getNonce(), "nonce");
+ Assert.assertEquals(unifiedHeader.getSignature(), "signed");
+ Assert.assertEquals(unifiedHeader.getSerial(), "serial-no");
+ }
}
From 3d8746e1b61975d7150df8884feb4d6a4ea8265f Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Tue, 18 Aug 2026 12:51:38 +0800
Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=E9=80=9A=E7=9F=A5?=
=?UTF-8?q?=E5=A4=B4=E7=BB=A7=E6=89=BF=E6=9E=84=E5=BB=BA=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../wxpay/bean/ecommerce/SignatureHeader.java | 14 ++------------
.../wxpay/bean/notify/SignatureHeader.java | 4 ++--
.../LegacyEcommerceApiCompatibilityTest.java | 11 ++++++-----
3 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
index fe7eee99b..cefac5a9d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
@@ -1,9 +1,9 @@
package com.github.binarywang.wxpay.bean.ecommerce;
import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
import java.io.Serializable;
@@ -14,22 +14,12 @@
* @author cloudX
*/
@Data
-@Builder
+@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Deprecated
public class SignatureHeader extends com.github.binarywang.wxpay.bean.notify.SignatureHeader implements Serializable {
private static final long serialVersionUID = -6958015499416059949L;
- /**
- * 时间戳
- */
- private String timeStamp;
-
- /**
- * 随机串
- */
- private String nonce;
-
/**
* 已签名字符串
*/
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java
index cd1fbc42d..1381759fd 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java
@@ -1,9 +1,9 @@
package com.github.binarywang.wxpay.bean.notify;
import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
import java.io.Serializable;
@@ -14,7 +14,7 @@
* @author thinstar
*/
@Data
-@Builder
+@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class SignatureHeader implements Serializable {
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
index 1b0e1302d..07030032d 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
@@ -29,11 +29,12 @@ public void shouldKeepLegacyRefundAndWithdrawNotificationSignatures() throws Exc
@Test
public void shouldMakeLegacyHeaderMoreSpecificAndPreserveSignatureFields() {
com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader legacyHeader =
- new com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader();
- legacyHeader.setTimeStamp("timestamp");
- legacyHeader.setNonce("nonce");
- legacyHeader.setSigned("signed");
- legacyHeader.setSerialNo("serial-no");
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.builder()
+ .timeStamp("timestamp")
+ .nonce("nonce")
+ .signed("signed")
+ .serialNo("serial-no")
+ .build();
Assert.assertTrue(com.github.binarywang.wxpay.bean.notify.SignatureHeader.class
.isAssignableFrom(legacyHeader.getClass()));
From 553ed89556dc5ea464c88e52ad25c7909c946f0a Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Tue, 18 Aug 2026 15:03:33 +0800
Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=E4=BF=9D=E6=8C=81=E6=97=A7=E9=80=9A?=
=?UTF-8?q?=E7=9F=A5=E5=A4=B4=E4=BA=8C=E8=BF=9B=E5=88=B6=E5=85=BC=E5=AE=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../wxpay/bean/ecommerce/SignatureHeader.java | 120 ++++++++++++++++--
.../LegacyEcommerceApiCompatibilityTest.java | 45 ++++++-
2 files changed, 155 insertions(+), 10 deletions(-)
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
index cefac5a9d..cbae86043 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/SignatureHeader.java
@@ -1,9 +1,9 @@
package com.github.binarywang.wxpay.bean.ecommerce;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.SuperBuilder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
import java.io.Serializable;
@@ -13,13 +13,14 @@
*
* @author cloudX
*/
-@Data
-@SuperBuilder
-@NoArgsConstructor
-@AllArgsConstructor
@Deprecated
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@ToString(callSuper = false)
public class SignatureHeader extends com.github.binarywang.wxpay.bean.notify.SignatureHeader implements Serializable {
private static final long serialVersionUID = -6958015499416059949L;
+
/**
* 已签名字符串
*/
@@ -29,4 +30,107 @@ public class SignatureHeader extends com.github.binarywang.wxpay.bean.notify.Sig
* 证书序列号
*/
private String serialNo;
+
+ /**
+ * 保留在旧类中的序列化字段,避免升级后反序列化旧数据时丢失。
+ */
+ private String timeStamp;
+
+ /**
+ * 保留在旧类中的序列化字段,避免升级后反序列化旧数据时丢失。
+ */
+ private String nonce;
+
+ public SignatureHeader() {
+ super();
+ }
+
+ /**
+ * 保留 4.8.4 及以前版本的构造器签名。
+ */
+ public SignatureHeader(String timeStamp, String nonce, String signed, String serialNo) {
+ setTimeStamp(timeStamp);
+ setNonce(nonce);
+ this.signed = signed;
+ this.serialNo = serialNo;
+ }
+
+ private SignatureHeader(SignatureHeaderBuilder builder) {
+ super(builder);
+ this.timeStamp = builder.timeStamp;
+ this.nonce = builder.nonce;
+ this.signed = builder.signed;
+ this.serialNo = builder.serialNo;
+ }
+
+ @Override
+ public String getTimeStamp() {
+ return this.timeStamp;
+ }
+
+ @Override
+ public void setTimeStamp(String timeStamp) {
+ super.setTimeStamp(timeStamp);
+ this.timeStamp = timeStamp;
+ }
+
+ @Override
+ public String getNonce() {
+ return this.nonce;
+ }
+
+ @Override
+ public void setNonce(String nonce) {
+ super.setNonce(nonce);
+ this.nonce = nonce;
+ }
+
+ /**
+ * 保留旧版 builder 的类型和方法返回值描述符。
+ */
+ public static SignatureHeaderBuilder builder() {
+ return new SignatureHeaderBuilder();
+ }
+
+ public static class SignatureHeaderBuilder extends com.github.binarywang.wxpay.bean.notify.SignatureHeader
+ .SignatureHeaderBuilder {
+ private String timeStamp;
+ private String nonce;
+ private String signed;
+ private String serialNo;
+
+ @Override
+ public SignatureHeaderBuilder timeStamp(String timeStamp) {
+ super.timeStamp(timeStamp);
+ this.timeStamp = timeStamp;
+ return this;
+ }
+
+ @Override
+ public SignatureHeaderBuilder nonce(String nonce) {
+ super.nonce(nonce);
+ this.nonce = nonce;
+ return this;
+ }
+
+ public SignatureHeaderBuilder signed(String signed) {
+ this.signed = signed;
+ return this;
+ }
+
+ public SignatureHeaderBuilder serialNo(String serialNo) {
+ this.serialNo = serialNo;
+ return this;
+ }
+
+ @Override
+ protected SignatureHeaderBuilder self() {
+ return this;
+ }
+
+ @Override
+ public SignatureHeader build() {
+ return new SignatureHeader(this);
+ }
+ }
}
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
index 07030032d..21f371d12 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/LegacyEcommerceApiCompatibilityTest.java
@@ -5,8 +5,12 @@
import org.testng.Assert;
import org.testng.annotations.Test;
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+import java.util.Base64;
+
/**
- * Compile-time compatibility checks for the pre-#4014 e-commerce API.
+ * Compatibility checks for the pre-#4014 e-commerce API.
*/
public class LegacyEcommerceApiCompatibilityTest {
@@ -27,7 +31,7 @@ public void shouldKeepLegacyRefundAndWithdrawNotificationSignatures() throws Exc
}
@Test
- public void shouldMakeLegacyHeaderMoreSpecificAndPreserveSignatureFields() {
+ public void shouldKeepLegacySignatureHeaderConstructorAndBuilderAbi() throws Exception {
com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader legacyHeader =
com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.builder()
.timeStamp("timestamp")
@@ -36,6 +40,14 @@ public void shouldMakeLegacyHeaderMoreSpecificAndPreserveSignatureFields() {
.serialNo("serial-no")
.build();
+ Assert.assertNotNull(com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.class.getConstructor(
+ String.class, String.class, String.class, String.class));
+ Assert.assertEquals(com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.SignatureHeaderBuilder.class,
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.SignatureHeaderBuilder.class
+ .getMethod("timeStamp", String.class).getReturnType());
+ Assert.assertEquals(com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.SignatureHeaderBuilder.class,
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader.SignatureHeaderBuilder.class
+ .getMethod("nonce", String.class).getReturnType());
Assert.assertTrue(com.github.binarywang.wxpay.bean.notify.SignatureHeader.class
.isAssignableFrom(legacyHeader.getClass()));
com.github.binarywang.wxpay.bean.notify.SignatureHeader unifiedHeader =
@@ -45,4 +57,33 @@ public void shouldMakeLegacyHeaderMoreSpecificAndPreserveSignatureFields() {
Assert.assertEquals(unifiedHeader.getSignature(), "signed");
Assert.assertEquals(unifiedHeader.getSerial(), "serial-no");
}
+
+ @Test
+ public void shouldIncludeTimestampAndNonceInLegacyHeaderEquality() {
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader first =
+ new com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader("timestamp-1", "nonce", "signed", "serial-no");
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader second =
+ new com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader("timestamp-2", "nonce", "signed", "serial-no");
+
+ Assert.assertNotEquals(first, second);
+ }
+
+ @Test
+ public void shouldReadLegacySerializedHeaderFields() throws Exception {
+ String legacySerializedHeader = "rO0ABXNyADpjb20uZ2l0aHViLmJpbmFyeXdhbmcud3hwYXkuYmVhbi5lY29tbWVyY2UuU2lnbmF0dXJlSGVhZGVyn3ApxLekv9MCAARMAAVub25jZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACHNlcmlhbE5vcQB+AAFMAAZzaWduZWRxAH4AAUwACXRpbWVTdGFtcHEAfgABeHB0AAVub25jZXQACXNlcmlhbC1ub3QABnNpZ25lZHQACXRpbWVzdGFtcA==";
+ ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(
+ Base64.getDecoder().decode(legacySerializedHeader)));
+ com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader header =
+ (com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader) input.readObject();
+
+ Assert.assertEquals(header.getTimeStamp(), "timestamp");
+ Assert.assertEquals(header.getNonce(), "nonce");
+ Assert.assertEquals(header.getSigned(), "signed");
+ Assert.assertEquals(header.getSerialNo(), "serial-no");
+ }
+
+ private void shouldCompileNullNotificationHeaderCalls(EcommerceService ecommerceService) throws Exception {
+ ecommerceService.parseRefundNotifyResult("notify-data", null);
+ ecommerceService.parseWithdrawNotifyResult("notify-data", null);
+ }
}