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 deserializers
p.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 case
try {
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 it = props.values().iterator();
while (it.hasNext()) {
POJOPropertyBuilder prop = it.next();
// 去除private属性,PId属性会在这里移除
if (!prop.anyVisible()) {
it.remove();
continue;
}
// Otherwise, check ignorals
if (prop.anyIgnorals()) {
// first: if one or more ignorals, and no explicit markers, remove the whole thing
if (!prop.isExplicitlyIncluded()) {
it.remove();
_collectIgnorals(prop.getName());
continue;
}
// otherwise just remove ones marked to be ignored
prop.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 rename
Iterator<Map.Entry<String,POJOPropertyBuilder>> it = props.entrySet().iterator();
LinkedList renamed = null;
while (it.hasNext()) {
Map.Entry<String, POJOPropertyBuilder> entry = it.next();
POJOPropertyBuilder prop = entry.getValue();
//被@JsonProperty注解的属性会找到对应的属性名
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
JVW-1715674943159)]
[外链图片转存中…(img-U5SqqNSL-1715674943159)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!