From ea047455e9d8d9341cb3b0f50863bd9f67c760f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:17:31 +0000 Subject: [PATCH 1/2] Initial plan From c938e078f0663fd82bb52abaf558e55c55804199 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:24:31 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A14.8.0=E7=89=88=E6=9C=ACMemChangeList=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E4=B8=BA=E7=A9=BA=E5=AD=97=E7=AC=A6=E4=B8=B2=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 XStreamCDataListConverter 兼容新旧两种格式: - 旧格式(4.8.0之前): - 新格式(4.8.0起): 解析结果统一为逗号分隔字符串,保持向后兼容。 Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com> --- .../util/xml/XStreamCDataListConverter.java | 54 +++++++++++++++++++ .../cp/bean/message/WxCpXmlMessage.java | 3 +- .../cp/bean/message/WxCpXmlMessageTest.java | 48 +++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamCDataListConverter.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamCDataListConverter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamCDataListConverter.java new file mode 100644 index 000000000..0b55a9c03 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/XStreamCDataListConverter.java @@ -0,0 +1,54 @@ +package me.chanjar.weixin.common.util.xml; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +/** + * 兼容两种格式的字符串列表转换器: + * + * 解析结果统一为逗号分隔的字符串。 + */ +public class XStreamCDataListConverter implements Converter { + + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + if (source != null) { + writer.setValue(""); + } + } + + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + if (reader.hasMoreChildren()) { + // 新格式:含有 子元素 + StringBuilder sb = new StringBuilder(); + while (reader.hasMoreChildren()) { + reader.moveDown(); + String value = reader.getValue(); + if (value != null && !value.isEmpty()) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(value); + } + reader.moveUp(); + } + return sb.length() > 0 ? sb.toString() : null; + } else { + // 旧格式:直接 CDATA 文本 + String value = reader.getValue(); + return (value != null && !value.isEmpty()) ? value : null; + } + } + + @Override + public boolean canConvert(Class type) { + return type == String.class; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java index 08a093631..6475623d8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java @@ -11,6 +11,7 @@ import me.chanjar.weixin.common.util.xml.IntegerArrayConverter; import me.chanjar.weixin.common.util.xml.LongArrayConverter; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; +import me.chanjar.weixin.common.util.xml.XStreamCDataListConverter; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; @@ -156,7 +157,7 @@ public class WxCpXmlMessage implements Serializable { private String memChangeCnt; @XStreamAlias("MemChangeList") - @XStreamConverter(value = XStreamCDataConverter.class) + @XStreamConverter(value = XStreamCDataListConverter.class) private String memChangeList; @XStreamAlias("LastMemVer") diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java index 0b2324a5f..e87ff2334 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java @@ -570,5 +570,53 @@ public void testExternalChatChangeEvent() { assertEquals(wxMessage3.getUpdateDetail(), "change_name"); // 当XML中没有MemChangeList元素时,字段应该为null而不是空字符串 assertThat(wxMessage3.getMemChangeList()).isNull(); + + // 测试企业微信4.8.0新格式:MemChangeList使用子元素(加群场景) + String xmlNewFormatAddMember = "" + + "" + + "" + + "9811170016713" + + "" + + "" + + "" + + "" + + "" + + "3" + + "1" + + "" + + "" + + "" + + ""; + WxCpXmlMessage wxMessage4 = WxCpXmlMessage.fromXml(xmlNewFormatAddMember); + assertEquals(wxMessage4.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CHAT); + assertEquals(wxMessage4.getChangeType(), "update"); + assertEquals(wxMessage4.getUpdateDetail(), "add_member"); + assertEquals(wxMessage4.getJoinScene(), "3"); + assertEquals(wxMessage4.getMemChangeCnt(), "1"); + // 新格式:子元素中的成员ID应被正确解析 + assertEquals(wxMessage4.getMemChangeList(), "wmxUBwDQAAO-Hn5_wFJz4wvo5TxLFibw"); + + // 测试企业微信4.8.0新格式:多个子元素(多成员变更) + String xmlNewFormatMultiMember = "" + + "" + + "" + + "1403610513" + + "" + + "" + + "" + + "" + + "" + + "1" + + "2" + + "" + + "" + + "" + + "" + + ""; + WxCpXmlMessage wxMessage5 = WxCpXmlMessage.fromXml(xmlNewFormatMultiMember); + assertEquals(wxMessage5.getUpdateDetail(), "del_member"); + assertEquals(wxMessage5.getMemChangeCnt(), "2"); + // 多个元素应被解析为逗号分隔字符串 + assertEquals(wxMessage5.getMemChangeList(), "wmEJiCwAAA9KG2qlSq6rKwASSgAAAA,wmEJiCwAAA9KG2qlSq6rKwBBBBBBB"); } }