简介

feign是一种声明式http请求调用方式,工作原理就是根据FeignClient注解生成新的接口(也就是传说中的动态代理),常见使用方式如下所示:

@FeignClient(name="UserFeignService",url="${auth.url}",fallbackFactory = OrgFeignServiceFallback.class,configuration = FeignErrorDecoderConfiguration.class)
public interface OrgFeignService {/*** * @param org* @return*/@PostMapping(value="Tenant/AddTenantOrg", consumes="application/json; charset=UTF-8")APIResultTO<TenantOrg> addOrg(OrgDto org, @RequestHeader("token")String token);
}

应用场景

1、序列化以及反序列化采用jackson

2、调用第三方采用feign注解式接口

问题分析

APIResultTO是一个api通用接口返回泛型类,TenantOrg为传入的具体泛型类,咱们来看下出问题的类:

@Getter
@Setter
@NoArgsConstructor
public class TenantOrg {/***/@JsonProperty("Id")private String Id;/*** 父级Id*/@JsonProperty("PId")private String PId;/*** 租户代码*/@JsonProperty("Tenant")private String tenant;/*** 组织架构名字*/@JsonProperty("Name")private String name;
}

必须要用@JsonProperty("Id")或者@JsonSetter("Id")注解来显示声明属性名字,尤其是首字母为大写的情况,否则反序列化后的数据就为空值。为什么TenantOrg类中的Id等其他属性跟第三方服务返回的json数据字段完全一致,却没有成功设置对应的属性呢,这个就要看下BeanDeserializer类的deserializeFromObject方法,从其名字上我们可以看出这是将请求返回的数据反序列化成对应的类对象:

public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) throws IOException{/* 09-Dec-2014, tatu: As per [databind#622], we need to allow Object Id references*   to come in as JSON Objects as well; but for now assume they will*   be simple, single-property references, which means that we can*   recognize them without having to buffer anything.*   Once again, if we must, we can do more complex handling with buffering,*   but let's only do that if and when that becomes necessary.*/if ((_objectIdReader != null) && _objectIdReader.maySerializeAsObject()) {if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)&& _objectIdReader.isValidReferencePropertyName(p.getCurrentName(), p)) {return deserializeFromObjectId(p, ctxt);}}if (_nonStandardCreation) {if (_unwrappedPropertyHandler != null) {return deserializeWithUnwrapped(p, ctxt);}if (_externalTypeIdHandler != null) {return deserializeWithExternalTypeId(p, ctxt);}Object bean = deserializeFromObjectUsingNonDefault(p, ctxt);if (_injectables != null) {injectValues(ctxt, bean);}/* 27-May-2014, tatu: I don't think view processing would work*   at this point, so commenting it out; but leaving in place*   just in case I forgot something fundamental...*//*if (_needViewProcesing) {Class<?> view = ctxt.getActiveView();if (view != null) {return deserializeWithView(p, ctxt, bean, view);}}*/return bean;}final Object bean = _valueInstantiator.createUsingDefault(ctxt);// [databind#631]: Assign current value, to be accessible by custom deserializersp.setCurrentValue(bean);if (p.canReadObjectId()) {Object id = p.getObjectId();if (id != null) {_handleTypedObjectId(p, ctxt, bean, id);}}if (_injectables != null) {injectValues(ctxt, bean);}if (_needViewProcesing) {Class<?> view = ctxt.getActiveView();if (view != null) {return deserializeWithView(p, ctxt, bean, view);}}if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {String propName = p.getCurrentName();do {p.nextToken();//如果要跟踪测试的话,直接定位到该位置就可以,你就会发现如果没有//JSONProperty之类的注解定义属性名字的话,Id、PId属性在_beanProperties都成了小写的属性SettableBeanProperty prop = _beanProperties.find(propName);if (prop != null) { // normal casetry {prop.deserializeAndSet(p, ctxt, bean);} catch (Exception e) {wrapAndThrow(e, bean, propName, ctxt);}continue;}handleUnknownVanilla(p, ctxt, bean, propName);} while ((propName = p.nextFieldName()) != null);}return bean;}

具体如下图所示:

正如上面所示,用@JsonProperty注解配置的属性,在反序列化时就按照@JsonProperty注解定义的属性名相同,至于为什么在TenantOrg中定义的PId属性在使用时怎么变成了pid,具体可以看下POJOPropertiesCollector类的_removeUnwantedProperties方法以及_renameProperties方法:

    protected void _removeUnwantedProperties(Map<String, POJOPropertyBuilder> props){Iterator<POJOPropertyBuilder> it = props.values().iterator();while (it.hasNext()) {POJOPropertyBuilder prop = it.next();// 去除private属性,PId属性会在这里移除if (!prop.anyVisible()) {it.remove();continue;}// Otherwise, check ignoralsif (prop.anyIgnorals()) {// first: if one or more ignorals, and no explicit markers, remove the whole thingif (!prop.isExplicitlyIncluded()) {it.remove();_collectIgnorals(prop.getName());continue;}// otherwise just remove ones marked to be ignoredprop.removeIgnored();if (!prop.couldDeserialize()) {_collectIgnorals(prop.getName());}}}}
protected void _renameProperties(Map<String, POJOPropertyBuilder> props){// With renaming need to do in phases: first, find properties to renameIterator<Map.Entry<String,POJOPropertyBuilder>> it = props.entrySet().iterator();LinkedList<POJOPropertyBuilder> renamed = null;while (it.hasNext()) {Map.Entry<String, POJOPropertyBuilder> entry = it.next();POJOPropertyBuilder prop = entry.getValue();//被@JsonProperty注解的属性会找到对应的属性名Collection<PropertyName> l = prop.findExplicitNames();// no explicit names? Implicit one is fine as isif (l.isEmpty()) {continue;}it.remove(); // need to replace with one or more renamedif (renamed == null) {renamed = new LinkedList<POJOPropertyBuilder>();}// simple renaming? Just do it//在这里使用@JsonProperty注解里面定义的属性名,比如PId、Id等//所以使用了@JsonProperty注解后,我们就无需关注类里面属性的大小写,设置不用关注属性名if (l.size() == 1) {PropertyName n = l.iterator().next();renamed.add(prop.withName(n));continue;}// but this may be problematic...renamed.addAll(prop.explode(l));/*String newName = prop.findNewName();if (newName != null) {if (renamed == null) {renamed = new LinkedList<POJOPropertyBuilder>();}prop = prop.withSimpleName(newName);renamed.add(prop);it.remove();}*/}// and if any were renamed, merge back in...if (renamed != null) {for (POJOPropertyBuilder prop : renamed) {String name = prop.getName();POJOPropertyBuilder old = props.get(name);if (old == null) {props.put(name, prop);} else {old.addAll(prop);}// replace the creatorProperty too, if there is one_updateCreatorProperty(prop, _creatorProperties);// [databind#2001]: New name of property was ignored previously? Remove from ignored// 01-May-2018, tatu: I have a feeling this will need to be revisited at some point,//   to avoid removing some types of removals, possibly. But will do for now.if (_ignoredPropertyNames != null) {_ignoredPropertyNames.remove(name);}}}}

feign接口返回泛型设置属性为null问题相关推荐

  1. vue根据接口返回数据状态给按钮动态设置disabled属性

    这里写自定义目录标题 1种 html data 方法 2种 html data 方法 最后 1种 html <b-button variant="success" @clic ...

  2. 利用ATL创建com组件和如何在程序中使用组件的接口函数和设置接口的属性

    这是一个ATL开发实例的流程: 1.       在atl中插入一个atl实例,然后添加一个类,派生自ccmdtarget. 2.       添加相应的属性或者方法,在这里需要明白一点的是,这个属性 ...

  3. 单独某个设置feign接口的超时时间

    1.在配置文件里配置:hystrix:enabled: true feign:httpclient.enable: falseokhttp.enable: true# 开启熔断hystrix:enab ...

  4. Java设置mysql字段为null_MySQL字段的属性应该尽量设置为NOT NULL

    数据库建表时,对于一些可填可不填的字段,我们应该尽量把它设置为 NOT NULL.这种做法即可以提高性能,又可以在很大程度上避免空指针类的问题,好处颇多. 1.节省空间 NULL 列需要更多的存储空间 ...

  5. QQ小程序解决方法:您的小程序分享功能缺失,为了方便用户分享传播,小程序主要页面请设置showShareItems参数属性为null或4个,这样用户可以将小程序直接转发给QQ好友、空间、微信和朋友圈

    提交QQ小程序,审核的时候,可能会被腾讯以如下理由拒绝审核: 您好,您的小程序分享功能缺失,为了方便用户分享传播,小程序主要页面请设置showShareItems参数属性为null或4个,这样用户可以 ...

  6. WebRTC Native M96 SDK接口封装--setVideoEncoderConfiguration设置本地视频的编码属性

    一系列云里雾里的介绍,最终还要回到接口的封装. 提供接口,给上层应用调用.今天,就聊一聊setVideoEncoderConfiguration,设置本地视频编码属性接口的实现. 接口定义(Agora ...

  7. Feign接口 多线程问题

    Spring Cloud Feign传输Header,并保证多线程情况下也适用 一.现象 微服务在生产中,常遇到需要把 header 传递到下一子服务的情况(如服务A访问服务B的接口,需要传递head ...

  8. Java 实现对象空属性转null

       简单写一个小工具实现对象空属性转null    最近的业务中,因为涉及到安全性的问题,接口请求对象和sql实体对象不是同一个对象,而是特意写了一个属性相差不大的对象作为请求对象;这样在操作sql ...

  9. 返回json格式 不忽略null字段

    返回json格式 不忽略null字段 发布于 353天前  作者 king666  271 次浏览  复制  上一个帖子  下一个帖子  标签: json 如题,一个实体的某个字段如果为null,在转 ...

  10. 分布式之API接口返回格式如何优雅设计?,苦熬一个月

    #2000-2999 区间表示用户错误 #3000-3999 区间表示接口异常 这样前端开发人员在得到返回值后,**根据状态码就可以知道,大概什么错误**,再根据message相关的信息描述,**可以 ...

最新文章

  1. 计算机应用专业能评自动化工程师吗,报考自动化控制工程师中级职称需要哪些条件?...
  2. 普元EOS开发积累第一篇(常见错误解决方法) 持续更新
  3. 题目1165:字符串匹配
  4. [codeigniter]CI中使用pChart绘制图表,已测通过
  5. C/C++ 语言中的表达式求值
  6. 物理搬砖问题_搬砖姿势:风法
  7. django模型的字段类型和关系
  8. opencv配置_Opencv在vs2012下的配置
  9. Python笔记-flask执行后台程序(非web应用)
  10. 小车自动往返工作原理_请把小车自动往返控制线路的工作原理描述一下。
  11. 《JavaScript构建Web和ArcGIS Server应用实战》——1.5 总结
  12. makefile中的wildcard和notdir和patsubst
  13. 串口的定义,232,485,UART,TTL之间的区别和关系到底是什么
  14. mysql中的预留字段_数据库设计误区:备用字段 / 保留字段 / 预留字段
  15. matlab dcm文件,CT的原始图像.dcm文件的读取
  16. oracle 还原imp,Oracle学习笔记——imp还原数据库
  17. Steam Deck 游戏掌机可运行 Windows
  18. Java带宽限速器、Springboot限速器
  19. 大疆创新2019校招
  20. 无插件纯Web HTML5 3D机房 进阶篇(新增设备、线缆、巡查等功能)

热门文章

  1. 3d游戏计算机怎么配置要求吗,3DMAX软件对电脑的配置要求
  2. 高等代数--线性空间
  3. MapReduce学习一些笔记
  4. 百度、太一云、趣链、星合、达令共议什么是真区块链【区块链打假】
  5. [CSP-S模拟测试]:Star Way To Heaven(最小生成树Prim)
  6. 【原创】谈谈个人与平台
  7. 信息安全-网络安全审计技术原理与应用
  8. timus 1741. Communication Fiend URAL 解题报告 DP+读题
  9. 调度算法学习_MIN-MIN及MAX-MIN算法
  10. 三国史诗——三国官制(二)