关键词

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.PageResult` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

版本信息

升级前版本

SpringBoot SpringCloud
2.0.6.RELEASE Finchley.SR2

升级后版本

SpringBoot SpringCloud
2.2.5.RELEASE Hoxton.SR3

错误内容(较长)

com.netflix.hystrix.exception.HystrixRuntimeException: ItemTemplateApiClient#searchAll(ItemTemplateSearchVo) failed and no fallback available.at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:822)at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:807)at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:140)at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)at com.netflix.hystrix.AbstractCommand$DeprecatedOnFallbackHookApplication$1.onError(AbstractCommand.java:1472)at com.netflix.hystrix.AbstractCommand$FallbackHookApplication$1.onError(AbstractCommand.java:1397)at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)at rx.observers.Subscribers$5.onError(Subscribers.java:230)at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:44)at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:28)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:142)at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$3.onError(AbstractCommand.java:1194)at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.onError(OperatorSubscribeOn.java:80)at rx.observers.Subscribers$5.onError(Subscribers.java:230)at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)at rx.observers.Subscribers$5.onError(Subscribers.java:230)at com.netflix.hystrix.AbstractCommand$DeprecatedOnRunHookApplication$1.onError(AbstractCommand.java:1431)at com.netflix.hystrix.AbstractCommand$ExecutionHookApplication$1.onError(AbstractCommand.java:1362)at rx.observers.Subscribers$5.onError(Subscribers.java:230)at rx.observers.Subscribers$5.onError(Subscribers.java:230)at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:44)at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:28)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10327)at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100)at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56)at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47)at org.springframework.cloud.sleuth.instrument.async.TraceCallable.call(TraceCallable.java:70)at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69)at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)at java.util.concurrent.FutureTask.run(FutureTask.java)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
Caused by: feign.codec.DecodeException: Type definition error: [simple type, class xxx.PageResult]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.PageResult` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)at [Source: (PushbackInputStream); line: 1, column: 8027] (through reference chain: xxx.Result["response"])at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:187)at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:147)at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:80)at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:109)at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302)at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46)... 28 common frames omitted
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class xxx.PageResult]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.PageResult` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)at [Source: (PushbackInputStream); line: 1, column: 8027] (through reference chain: xxx.Result["response"])at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:246)at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:228)at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:104)at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:59)at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:62)at feign.optionals.OptionalDecoder.decode(OptionalDecoder.java:36)at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:183)... 34 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `xxx.PageResult` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)at [Source: (PushbackInputStream); line: 1, column: 8027] (through reference chain: xxx.Result["response"])at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1589)at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1055)at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:369)at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3258)at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:240)... 40 common frames omitted

错误原因

很明显说我的PageResult没有构造函数, 我给PageResult加上构造函数即可

但是为什么升级之前又可以呢?

源码分析(jackson)

这里我绕了点弯路, 我去分析了jackson反序列化的源码, 但最后发现根本就不是jackson的问题,而是lombok的问题

jackson的调试有点艰辛, 仅贴出部分追踪到的核心代码

首先已知我的Fegin接口返回类型为Result<PageResult<ItemVo>>, 属于多层泛型, 问题就在中间PageResult无法反序列化

第一阶段分析到处理对象实例化的代码,和设置对象属性的核心代码

com.fasterxml.jackson.databind.deser.BeanDeserializer#deserializeFromObject

/*** General version used when handling needs more advanced features.*/
// 本方法会递归执行, 将对象所有层次的值设置完@Overridepublic 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)) {// 这里是获得接口返回json中key值String propName = p.getCurrentName();do {p.nextToken();// 这里寻找创建出来的Bean对象对应json的key的字段描述SettableBeanProperty prop = _beanProperties.find(propName);if (prop != null) { // normal casetry {// 这里就是将值设置到Bean字段里, 如果Bean的字段类型为泛型, 内部继续递归的调用本方法, 直到递归完所有层次的字段值(树状递归)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;}

创建Bean的方法

com.fasterxml.jackson.databind.deser.std.StdValueInstantiator#createUsingDefault

    @Overridepublic Object createUsingDefault(DeserializationContext ctxt) throws IOException{// 判断是否有默认构造函数if (_defaultCreator == null) { // sanity-check; caller should check// 没有无参构造抛异常return super.createUsingDefault(ctxt);}try {// 有无参构造则调用创建Beanreturn _defaultCreator.call();} catch (Exception e) { // 19-Apr-2017, tatu: Let's not catch Errors, just Exceptionsreturn ctxt.handleInstantiationProblem(_valueClass, null, rewrapCtorProblem(ctxt, e));}}

然后去分析_defaultCreator 属性是从哪里赋值的

com.fasterxml.jackson.databind.deser.std.StdValueInstantiator#StdValueInstantiator(com.fasterxml.jackson.databind.deser.std.StdValueInstantiator)

protected StdValueInstantiator(StdValueInstantiator src){_valueTypeDesc = src._valueTypeDesc;_valueClass = src._valueClass;// 这里传进来的_defaultCreator = src._defaultCreator;_constructorArguments = src._constructorArguments;_withArgsCreator = src._withArgsCreator;_delegateType = src._delegateType;_delegateCreator = src._delegateCreator;_delegateArguments = src._delegateArguments;_arrayDelegateType = src._arrayDelegateType;_arrayDelegateCreator = src._arrayDelegateCreator;_arrayDelegateArguments = src._arrayDelegateArguments;_fromStringCreator = src._fromStringCreator;_fromIntCreator = src._fromIntCreator;_fromLongCreator = src._fromLongCreator;_fromDoubleCreator = src._fromDoubleCreator;_fromBooleanCreator = src._fromBooleanCreator;}

在这里下断点后,向调用栈向上找, 然后发现居然来自缓存= =!!

com.fasterxml.jackson.databind.deser.DeserializerCache#_cachedDeserializers

final protected LRUMap<JavaType, JsonDeserializer<Object>> _cachedDeserializers;

然后分析VO描述是怎么存到缓存里的

com.fasterxml.jackson.databind.deser.DeserializerCache#_createDeserializer

/*** Method that does the heavy lifting of checking for per-type annotations,* find out full type, and figure out which actual factory method* to call.*/@SuppressWarnings("unchecked")protected JsonDeserializer<Object> _createDeserializer(DeserializationContext ctxt,DeserializerFactory factory, JavaType type)throws JsonMappingException{final DeserializationConfig config = ctxt.getConfig();// First things first: do we need to use abstract type mapping?if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) {type = factory.mapAbstractType(config, type);}
// 这里会先初始化类的描述信息, 但是还没有触发找构造函数的代码BeanDescription beanDesc = config.introspect(type);// Then: does type define explicit deserializer to use, with annotation(s)?JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt,beanDesc.getClassInfo());if (deser != null) {return deser;}// If not, may have further type-modification annotations to check:JavaType newType = modifyTypeByAnnotation(ctxt, beanDesc.getClassInfo(), type);if (newType != type) {type = newType;beanDesc = config.introspect(newType);}// We may also have a Builder type to consider...Class<?> builder = beanDesc.findPOJOBuilder();if (builder != null) {return (JsonDeserializer<Object>) factory.createBuilderBasedDeserializer(ctxt, type, beanDesc, builder);}// Or perhaps a Converter?Converter<Object,Object> conv = beanDesc.findDeserializationConverter();if (conv == null) { // nope, just construct in normal way
// 从此处初始化, 传入类的描述信息return (JsonDeserializer<Object>) _createDeserializer2(ctxt, factory, type, beanDesc);}// otherwise need to do bit of introspectionJavaType delegateType = conv.getInputType(ctxt.getTypeFactory());// One more twist, as per [databind#288]; probably need to get new BeanDescif (!delegateType.hasRawClass(type.getRawClass())) {beanDesc = config.introspect(delegateType);}return new StdDelegatingDeserializer<Object>(conv, delegateType,_createDeserializer2(ctxt, factory, delegateType, beanDesc));}

省略一下步骤...(有点多), 而且都不重要, 都是一直向下传递beanDesc这个对象

com.fasterxml.jackson.databind.deser.BasicDeserializerFactory#_constructDefaultValueInstantiator

/*** Method that will construct standard default {@link ValueInstantiator}* using annotations (like @JsonCreator) and visibility rules*/protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationContext ctxt,BeanDescription beanDesc)throws JsonMappingException{CreatorCollector creators = new CreatorCollector(beanDesc, ctxt.getConfig());AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();// need to construct suitable visibility checker:final DeserializationConfig config = ctxt.getConfig();VisibilityChecker<?> vchecker = config.getDefaultVisibilityChecker(beanDesc.getBeanClass(),beanDesc.getClassInfo());/* 24-Sep-2014, tatu: Tricky part first; need to merge resolved property information*  (which has creator parameters sprinkled around) with actual creator*  declarations (which are needed to access creator annotation, amongst other things).*  Easiest to combine that info first, then pass it to remaining processing.*//* 15-Mar-2015, tatu: Alas, this won't help with constructors that only have implicit*   names. Those will need to be resolved later on.*/Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorDefs = _findCreatorsFromProperties(ctxt,beanDesc);// Important: first add factory methods; then constructors, so// latter can override former!
// 添加工厂方法, 这里边触发的找构造方法的代码_addDeserializerFactoryMethods(ctxt, beanDesc, vchecker, intr, creators, creatorDefs);// constructors only usable on concrete types:if (beanDesc.getType().isConcrete()) {
// 设置一下要调用的(无参)构造方法_addDeserializerConstructors(ctxt, beanDesc, vchecker, intr, creators, creatorDefs);}
// 调用构造方法初始化对象return creators.constructValueInstantiator(ctxt);}

然后一堆代码, 都不重要, 看到代码

com.fasterxml.jackson.databind.deser.BasicDeserializerFactory#_addDeserializerFactoryMethods

// 触发点在beanDesc.getFactoryMethods()
for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
...
}

com.fasterxml.jackson.databind.introspect.BasicBeanDescription#getFactoryMethods

    /*/**********************************************************/* Introspection for deserialization, factories/***********************************************************/@Overridepublic List<AnnotatedMethod> getFactoryMethods(){// must filter out anything that clearly is not a factory method
// 这里获得所有构造方法List<AnnotatedMethod> candidates = _classInfo.getFactoryMethods();if (candidates.isEmpty()) {return candidates;}List<AnnotatedMethod> result = null;for (AnnotatedMethod am : candidates) {if (isFactoryMethod(am)) {if (result == null) {result = new ArrayList<AnnotatedMethod>();}result.add(am);}}if (result == null) {return Collections.emptyList();}return result;}

com.fasterxml.jackson.databind.introspect.AnnotatedClass#getFactoryMethods

    public List<AnnotatedMethod> getFactoryMethods() {return _creators().creatorMethods;}

嗯里边是懒加载的方式初始化的, 初始化过一次后就保存到成员变量里

com.fasterxml.jackson.databind.introspect.AnnotatedClass#_creators

    private final Creators _creators() {Creators c = _creators;if (c == null) {if (_type == null) {c = NO_CREATORS;} else {
// 这里初始化该类的所有构造方法的调用描述, 包括有参和无参构造c = AnnotatedCreatorCollector.collectCreators(_annotationIntrospector,this, _type, _primaryMixIn);}_creators = c;}return c;}

com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector#collectCreators

public static Creators collectCreators(AnnotationIntrospector intr,TypeResolutionContext tc, JavaType type, Class<?> primaryMixIn){// Constructor also always members of resolved class, parent == resolution contextreturn new AnnotatedCreatorCollector(intr, tc)
// 代码在这里.collect(type, primaryMixIn);}Creators collect(JavaType type, Class<?> primaryMixIn){// 30-Apr-2016, tatu: [databind#1215]: Actually, while true, this does//   NOT apply to context since sub-class may have type bindings
//        TypeResolutionContext typeContext = new TypeResolutionContext.Basic(_typeFactory, _type.getBindings());
// 获取所有构造方法List<AnnotatedConstructor> constructors = _findPotentialConstructors(type, primaryMixIn);List<AnnotatedMethod> factories = _findPotentialFactories(type, primaryMixIn);/* And then... let's remove all constructors that are deemed* ignorable after all annotations have been properly collapsed.*/// AnnotationIntrospector is null if annotations not enabled; if so, can skip:if (_intr != null) {if (_defaultConstructor != null) {if (_intr.hasIgnoreMarker(_defaultConstructor)) {_defaultConstructor = null;}}// count down to allow safe removalfor (int i = constructors.size(); --i >= 0; ) {if (_intr.hasIgnoreMarker(constructors.get(i))) {constructors.remove(i);}}for (int i = factories.size(); --i >= 0; ) {if (_intr.hasIgnoreMarker(factories.get(i))) {factories.remove(i);}}}return new AnnotatedClass.Creators(_defaultConstructor, constructors, factories);}

这里就是对类的所有构造方法封装成描述对象的方法了

com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector#_findPotentialConstructors

/*** Helper method for locating constructors (and matching mix-in overrides)* we might want to use; this is needed in order to mix information between* the two and construct resulting {@link AnnotatedConstructor}s*/private List<AnnotatedConstructor> _findPotentialConstructors(JavaType type,Class<?> primaryMixIn){ClassUtil.Ctor defaultCtor = null;List<ClassUtil.Ctor> ctors = null;// 18-Jun-2016, tatu: Enum constructors will never be useful (unlike//    possibly static factory methods); but they can be royal PITA//    due to some oddities by JVM; see://    [https://github.com/FasterXML/jackson-module-parameter-names/issues/35]//    for more. So, let's just skip them.
// 判断类是否不为枚举类if (!type.isEnumType()) {
// 通过工具类获取该类的所有构造方法ClassUtil.Ctor[] declaredCtors = ClassUtil.getConstructors(type.getRawClass());
// 一下创建内部维护的构造函数描述成员变量for (ClassUtil.Ctor ctor : declaredCtors) {if (!isIncludableConstructor(ctor.getConstructor())) {continue;}if (ctor.getParamCount() == 0) {
// 参数数量为0个的设为无参的默认构造器defaultCtor = ctor;} else {if (ctors == null) {ctors = new ArrayList<>();}ctors.add(ctor);}}}List<AnnotatedConstructor> result;int ctorCount;if (ctors == null) {result = Collections.emptyList();// Nothing found? Short-circuitif (defaultCtor == null) { return result;}ctorCount = 0;} else {ctorCount = ctors.size();result = new ArrayList<>(ctorCount);for (int i = 0; i < ctorCount; ++i) {result.add(null);}}// primaryMixIn 为 null, 这里不会执行// so far so good; but do we also need to find mix-ins overrides?if (primaryMixIn != null) {MemberKey[] ctorKeys = null;for (ClassUtil.Ctor mixinCtor : ClassUtil.getConstructors(primaryMixIn)) {if (mixinCtor.getParamCount() == 0) {if (defaultCtor != null) {_defaultConstructor = constructDefaultConstructor(defaultCtor, mixinCtor);defaultCtor = null;}continue;}if (ctors != null) {if (ctorKeys == null) {ctorKeys = new MemberKey[ctorCount];for (int i = 0; i < ctorCount; ++i) {ctorKeys[i] = new MemberKey(ctors.get(i).getConstructor());}}MemberKey key = new MemberKey(mixinCtor.getConstructor());for (int i = 0; i < ctorCount; ++i) {if (key.equals(ctorKeys[i])) {result.set(i,constructNonDefaultConstructor(ctors.get(i), mixinCtor));break;}}}}}// Ok: anything within mix-ins has been resolved; anything remaining we must resolveif (defaultCtor != null) {
// 这里就会设置默认的无参构造器, 然后供后续操作初始化该类, 如果上边没有做找到defaultCtor的话_defaultConstructor就会是null, 后边jackson返序列化就会报无默认构造器异常_defaultConstructor = constructDefaultConstructor(defaultCtor, null);}for (int i = 0; i < ctorCount; ++i) {AnnotatedConstructor ctor = result.get(i);if (ctor == null) {result.set(i,constructNonDefaultConstructor(ctors.get(i), null));}}return result;}

看看他获取构造器的工具类代码, 很简单就是用jdkClass提供的getDeclaredConstructors()方法获取所有构造方法,包括私有的然后封装成自定义的对象就返回了

com.fasterxml.jackson.databind.util.ClassUtil#getConstructors

    public static Ctor[] getConstructors(Class<?> cls) {// Note: can NOT skip abstract classes as they may be used with mix-ins// and for regular use shouldn't really matter.if (cls.isInterface() || isObjectOrPrimitive(cls)) {return NO_CTORS;}Constructor<?>[] rawCtors = cls.getDeclaredConstructors();final int len = rawCtors.length;Ctor[] result = new Ctor[len];for (int i = 0; i < len; ++i) {result[i] = new Ctor(rawCtors[i]);}return result;}

看到getDeclaredConstructors()后我蒙了, 我断点下用idea执行器试了下还真的获取不到无参构造,

然后在项目中弄了个测试类去调PageResult.class的getDeclaredConstructors方法确实获取不到

那为啥升级前就行? 我回退了版本然后调测试类, 发现居然能获取到一个私有的无参构造器.

然后我看了一下VO...上边有一个注解@Data, 然后分别查看了两个版本编译后的class文件, 一个有私有无参构造, 一个没有

问题原因

我升级了SpringBoot后lombok的版本也升级了, 从1.16.22升级到了1.18.12

新版本lombok的@Data注解不会自动生成无参构造函数, 而旧版本的会生成一个私有的无参构造函数.

思考

总以为是框架问题, 但错误提示很清楚的说了是构造器找不到, 直接去对比下两个版本编译后的class文件就知道是lombok的问题.

我本以为旧版jackson的会自动识别并使用有参构造器来初始化类(感觉比较智能), 分析源码后发现人家从旧版到新版这部分类初始化的代码就没改过,哈哈哈 是我想太多了.

升级SpringCloud到Hoxton.SR3后使用Fegin出现jackson反序列化失败,源码分析,原因lombok版本升级相关推荐

  1. 升级SpringCloud到Hoxton.SR3出现The bean 'xxx.FeignClientSpecification' could not be registered. 源码分析和解决

    最近提升项目的SpringCloud版本后出错误导致项目无法启动 关键词 The bean 'xxx.FeignClientSpecification' could not be registered ...

  2. hbuilderx升级3.6.5版本后运行到手机端同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示

    问题1: hbuilderx升级3.6.5版本后运行到手机端同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示. 解决问题指路. https://uniapp.dclou ...

  3. [Vue源码分析]谷歌翻译后,Vue双向数据绑定失效了?

    前言: 最近运营反馈了一个问题:谷歌浏览器打开第三方储值平台,使用谷歌浏览器自带的翻译功能后,选择商品没有计算总额. 首先可以肯定的是这不是bug,这个平台已经兼容了13种语言,只是运营没有通过语言栏 ...

  4. F2FS源码分析-5.2 [数据恢复流程] 后滚恢复和Checkpoint的作用与实现

    F2FS源码分析系列文章 主目录 一.文件系统布局以及元数据结构 二.文件数据的存储以及读写 三.文件与目录的创建以及删除(未完成) 四.垃圾回收机制 五.数据恢复机制 数据恢复的原理以及方式 后滚恢 ...

  5. 【SpringCloud系列】服务注册与发现 - Eureka Server源码分析(2)

    3.6.Eureka Server 源码分析 上一篇文章简单介绍了 Eureka 的一些概念,今天咱们来看看其原理和源码,首先先看 Eureka Server 的原理. 3.6.1.Eureka Se ...

  6. 【SpringCloud微服务】第3章 服务治理SpringCloudEureka(五)——Eureka源码分析

    2.8 Eureka 源码分析   首先,对于服务注册中心.服务提供者.服务消费者这三个主要元素来说,后两者(也就是Eureka客户端)在整个运行机制中是大部分通信行为的主动发起者,而注册中心主要是处 ...

  7. 【SemiDrive源码分析】【X9芯片启动流程】27 - AP1 Android Preloader启动流程分析(加载atf、tos、bootloader镜像后进入BL31环境)

    [SemiDrive源码分析][X9芯片启动流程]27 - AP1 Android Preloader启动流程分析(加载atf.tos.bootloader镜像后进入BL31环境) 一.Android ...

  8. 基于TCP网络通信的自动升级程序源码分析-客户端接收文件

    升级程序客户端接收文件 /// <summary>/// 文件数据缓存 索引是 ConnectionInfo对象 数据包的顺序号 值是数据/// </summary>Dicti ...

  9. 【无标题】servlet配置后,浏览器上总显示jsp源码的问题

    这两天在idea,servlet配置后,浏览器上总显示jsp源码的问题,起初我是以为因为自己写的jsp要请求servlet页面,但是想想,那样的话浏览器也影响该先显示jsp吧,我搜了一下,jsp页面由 ...

最新文章

  1. linux双网卡绑定+单网卡多IP绑定
  2. python 常用内置函数_Python小白必备的8个最常用的内置函数(推荐)
  3. 如何解决 SQL Server 安装程序中的 COM+ 系统配置检查失败问题
  4. (JAVA)超大整数运算
  5. 研究综述 | 知识图谱划分算法研究综述
  6. vivox50pro鸿蒙系统,小米10至尊纪念版和vivox50pro+哪一款手机好
  7. C#项目打包后安装的桌面快捷方式图标怎么设置成自己想要的图标
  8. 如何编写可移植的c/c++代码
  9. 【集训队作业】IOI 2020 集训队作业 试题泛做 8
  10. 【信号检测】基于matlab双稳随机共振微弱信号检测【含Matlab源码 1701期】
  11. vsr matlab仿真,电压型PWM整流器(VSR)及控制系统的matlab仿真..docx
  12. 三星为Ativ S发布WP8更新
  13. 2022美国科学院院士名单公布:图灵奖得主、龙书作者Alfred V. Aho当选!
  14. java模拟手机号码发短信_java实现发送手机短信
  15. c++调用静态函数的方法
  16. Spark SQL架构工作原理及流程解析
  17. 苹果或挖走Meta AR公关总监,2022年的头显是真的要来了?
  18. 读 伯罗奔尼撒战争史
  19. Git常用命令学习手册
  20. 使用Arduino的LC电表:测量电感和频率

热门文章

  1. DSMM 模型talk
  2. 数据挖掘方法论及实施步骤
  3. 基于单片机的智能安防系统
  4. 在网页中调用打印预览及打印设置
  5. 计算机成就未来作文,【精选】成就未来作文4篇
  6. SuperMap iDesktop 10i加载百度地图为底图
  7. 树莓派初体验,超级便宜的服务器~
  8. 汇川技术小型PLC梯形图编程系列教程(二):AutoShop软件使用技巧介绍
  9. 碰到的Link2005错误的解决办法
  10. ddr4 dqs 频率_DDR工作原理_DDR DQS信号的处理