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"); } }