解决feign接口返回泛型设置属性为null的问题

网友投稿 1748 2023-01-05

解决feign接口返回泛型设置属性为null的问题

解决feign接口返回泛型设置属性为null的问题

简介

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 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 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 {

GUKbcIoFm 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 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());

http:// }

}

}

}

protected void _renameProperties(Map props)

{

// With renaming need to do in phases: first, find properties to rename

Iterator> it = props.entrySet().iterator();

LinkedList renamed = null;

while (it.hasNext()) {

Map.Entry entry = it.next();

POJOPropertyBuilder prop = entry.getValue();

//被@JsonProperty注解的属性会找到对应的属性名

Collection l = prop.findExplicitNames();

// no explicit names? Implicit one is fine as is

if (l.isEmpty()) {

continue;

}

it.remove(); // need to replace with one or more renamed

if (renamed == null) {

renamed = new LinkedList();

}

// 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();

}

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

}

}

}

}

springcloud feign请求:数据返回null

问题描述

调用方调用服务,DEBUG被调用方服务得到正确数据,但调用方返回的数据对象属性全为null

原因及解决方法:

在feign调用接口中与被调用方接口返回类型不一致。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:软件类移动应用开发(软件类移动应用开发是什么)
下一篇:招商银行小程序出售卡骗局(招商银行小程序出售卡骗局揭秘)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~