最近在一个项目中需要调用另外一个服务,而被调用服务的API提交ContentType为application/x-www-form-urlencoded,这个FeignClient也是支持的,在调用端的interface中定义方法,@RequestMapping参数指定具体类型就可以了,定义如下所示:
@RequestMapping(path = "/task/update", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
Response<String> updateTask(@RequestBody TaskRequest request);
遇到的问题:若上面的请求POJO结构TaskRequest继承于其他POJO时,父类的字段全部不会被Feign调用传送给请求的服务,造成请求失败。
原因分析:经过一番代码跟踪,发现这个由于Feign的内部实现决定,由于请求传送的Form字段,Feign通过feign.form.util.PojoUtil.toMap这个方法将PoJo中的成员字段反射解析出来,拼接为Form字段,而反射时它使用的是getDeclaredFields()这个方法,这造成只能取到当前类中定义的字段,即使父类中的变量修饰符为public,也会取不到。具体代码如下,关键位置是第9行的Field[] var4 = type.getDeclaredFields();
public static Map<String, Object> toMap(@NonNull Object object) {
try {
if (object == null) {
throw new NullPointerException("object is marked @NonNull but is null");
} else {
HashMap<String, Object> result = new HashMap();
Class<?> type = object.getClass();
PojoUtil.SetAccessibleAction setAccessibleAction = new PojoUtil.SetAccessibleAction();
Field[] var4 = type.getDeclaredFields();
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
Field field = var4[var6];
int modifiers = field.getModifiers();
if (!Modifier.isFinal(modifiers) && !Modifier.isStatic(modifiers)) {
setAccessibleAction.setField(field);
AccessController.doPrivileged(setAccessibleAction);
Object fieldValue = field.get(object);
if (fieldValue != null) {
String propertyKey = field.isAnnotationPresent(FormProperty.class) ? ((FormProperty)field.getAnnotation(FormProperty.class)).value() : field.getName();
result.put(propertyKey, fieldValue);
}
}
}
return result;
}
} catch (Throwable var11) {
throw var11;
}
}
结论:若是FeignClient调用服务的请求内容类型为form表单提交方式,使用POJO定义请求数据类型时,需避免类的继承情况。