企业微信人事助手api响应序列化问题#3977
Conversation
softboy99
commented
May 7, 2026
merge latest from fork source
…参数不符合系统要求,需要参照具体API接口说明,微信原始报文:{"errcode":40058,"errmsg":"invalid Request Parameter
…rvice.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…pHrServiceImpl.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…rvice.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…序列化问题;UpdateEmployeeFieldInfo暂时未用到,未做测试
🤖 Augment PR SummarySummary: This PR fixes 企业微信「人事助手」相关接口的响应反序列化/字段映射不一致问题,并补充向后兼容的字段/方法。 Changes:
Technical Notes: 新增了 mobile 值的对象结构(国家码/手机号)以及 option 列表的新版/旧版兼容结构;整体意图是与官方返回字段名保持一致并为旧 API 入口提供平滑过渡。 🤖 Was this summary useful? React with 👍 or 👎 |
| <suiteXmlFiles> | ||
| <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile> | ||
| </suiteXmlFiles> | ||
| <argLine> |
There was a problem hiding this comment.
weixin-java-cp/pom.xml:128: These --add-opens JVM args are only supported on Java 9+, so if this module’s tests are ever executed on JDK8 the forked test JVM will fail to start. Consider guarding this configuration so it only applies on JDK9+ runs.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| * 2: 单选/多选 | ||
| * 3: 日期 | ||
| */ | ||
| @SerializedName("field_type") |
There was a problem hiding this comment.
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldInfo.java:38: The new field_type value description (1/2/3) conflicts with WxCpHrFieldType (where 2 maps to DATE, 4/5 map to select types), which could make getFieldTypeEnum() misleading/incorrect. Could you double-check the field_type codes against the actual HR API response and keep the enum/docs consistent?
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| @Deprecated | ||
| public List<WxCpHrEmployeeFieldInfo> getFieldInfoList() { | ||
| if (groupList == null || groupList.isEmpty()) { | ||
| return null; |
There was a problem hiding this comment.
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldInfoResp.java:37: getFieldInfoList() returns null when groupList is empty, which may break older callers that iterate the list (previously they could reasonably expect an empty list). Returning an empty list would be a safer backward-compat behavior for this deprecated shim.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| */ | ||
| @SerializedName("field_key") | ||
| private String fieldKey; | ||
| @SerializedName("fieldid") |
There was a problem hiding this comment.
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldData.java:121: FieldItem no longer has the old fieldKey/field_key property, which is a source-level breaking change for existing update code even though other compatibility shims were added elsewhere. If the API still accepts field_key in some scenarios, consider keeping a deprecated alias to reduce upgrade pain.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| for (me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldInfo field : group.getFieldList()) { | ||
| System.out.println(" - 字段: " + field.getFieldName() + " (ID: " + field.getFieldId() + ", 类型: " + field.getFieldType() + ")"); | ||
| // 记录第一个字段ID用于测试 | ||
| if (firstFieldId == null && field.getFieldId() != null) { |
There was a problem hiding this comment.
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpHrServiceImplTest.java:172: Picking the first fieldId and always sending a text value (setTextValue(...)) can cause this integration test to fail if the first field is non-text, read-only, or otherwise not writable. This makes the test order-dependent/flaky across different tenants’ field configurations.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Pull request overview
该 PR 旨在修复企业微信「人事助手」相关接口在响应反序列化时字段结构与实际 API 返回不一致导致的解析问题,通过调整 HR 相关 Bean 的 @SerializedName 映射与数据结构,并补充对应的接口测试覆盖。
Changes:
- 调整 HR 字段定义/员工档案数据响应的字段映射,使其与实际返回的
group_list、field_info等结构对齐,并提供部分旧方法名的兼容入口。 - 扩展
WxCpHrEmployeeFieldInfo/WxCpHrEmployeeFieldData的字段模型以承载更多返回信息(字段ID、值类型、选项等)。 - 新增
WxCpHrServiceImplTest到 TestNG suite,并在weixin-java-cp模块 surefire 配置中加入 JVM--add-opens参数。
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| weixin-java-cp/src/test/resources/testng.xml | 将 HR API 测试类加入 TestNG suite 以执行验证 |
| weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpHrServiceImplTest.java | 更新/增强 HR 接口集成测试用例 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldInfoResp.java | 将字段定义响应调整为按分组返回(group_list)并提供旧 getter 兼容 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldInfo.java | 扩展字段定义模型(fieldId/optionList/valueType 等)并尝试兼容旧字段 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldDataResp.java | 将员工档案数据响应映射改为 field_info 并保留旧方法名 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/hr/WxCpHrEmployeeFieldData.java | 将单条档案数据建模为“单个字段数据”,补齐 value_* 等返回字段,并调整更新请求字段 |
| weixin-java-cp/pom.xml | surefire 增加 --add-opens 相关 JVM 参数以支持反射访问 |
| @Deprecated | ||
| public List<WxCpHrEmployeeFieldInfo> getFieldInfoList() { | ||
| if (groupList == null || groupList.isEmpty()) { | ||
| return null; | ||
| } | ||
| // 兼容旧版本:将所有分组的字段合并到一个列表 | ||
| List<WxCpHrEmployeeFieldInfo> allFields = new java.util.ArrayList<>(); | ||
| for (FieldGroup group : groupList) { | ||
| if (group.getFieldList() != null) { | ||
| allFields.addAll(group.getFieldList()); | ||
| } | ||
| } | ||
| return allFields.isEmpty() ? null : allFields; | ||
| } |
| * 选项ID. | ||
| */ | ||
| @SerializedName("id") | ||
| private Integer id; | ||
|
|
||
| /** | ||
| * 选项值. | ||
| */ | ||
| @SerializedName("value") | ||
| private String value; |
| */ | ||
| @SerializedName("option_list") | ||
| private List<Option> optionList; | ||
| private List<OldOption> optionList; |
| /** | ||
| * 字段key. | ||
| * 字段ID. | ||
| */ | ||
| @SerializedName("field_key") | ||
| private String fieldKey; | ||
| @SerializedName("fieldid") | ||
| private Integer fieldId; | ||
|
|
||
| /** | ||
| * 字段值. | ||
| * 字段值对象(推荐使用,支持多种类型). | ||
| */ | ||
| @SerializedName("field_value") | ||
| private WxCpHrEmployeeFieldValue fieldValue; | ||
|
|
||
| /** | ||
| * 字符串值(简化用法,适用于文本类型字段). | ||
| */ | ||
| @SerializedName("value_string") | ||
| private String valueString; |
| <configuration> | ||
| <suiteXmlFiles> | ||
| <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile> | ||
| </suiteXmlFiles> | ||
| <argLine> | ||
| --add-opens java.base/java.lang=ALL-UNNAMED | ||
| --add-opens java.base/java.lang.reflect=ALL-UNNAMED | ||
| --add-opens java.base/java.io=ALL-UNNAMED | ||
| --add-opens java.base/java.security=ALL-UNNAMED | ||
| --add-opens java.base/java.util=ALL-UNNAMED | ||
| --add-opens java.management/javax.management=ALL-UNNAMED | ||
| --add-opens java.naming/javax.naming=ALL-UNNAMED | ||
| </argLine> |
| WxCpHrEmployeeFieldInfoResp fieldInfoResp = hrService.getFieldInfo(null); | ||
| java.util.Map<Integer, me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldInfo> fieldInfoMap = new java.util.HashMap<>(); | ||
| java.util.Map<Integer, String> groupNameMap = new java.util.HashMap<>(); | ||
|
|
| System.out.println("分组: " + group.getGroupName() + " (ID: " + group.getGroupId() + ")"); | ||
| if (group.getFieldList() != null) { | ||
| for (me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldInfo field : group.getFieldList()) { | ||
| System.out.println(" - 字段: " + field.getFieldName() + " (ID: " + field.getFieldId() + ", 类型: " + field.getFieldType() + ")"); |