接上一篇:spring boot 是如何利用jackson进行反序列化的?

@RestController
public class HelloController {@RequestMapping("/")public BillSearch hello(@RequestBody BillSearch search) {return search;}
}

返回的search是如何序列化json的?

上一篇说到RequestResponseBodyMethodProcessor这个类在json序列化和反序列化都中很重要:

protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);Assert.state(servletRequest != null, "No HttpServletRequest");ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);Object arg = readWithMessageConverters(inputMessage, parameter, paramType);if (arg == null && checkRequired(parameter)) {throw new HttpMessageNotReadableException("Required request body is missing: " +parameter.getExecutable().toGenericString(), inputMessage);}return arg;}

上面是反序列化时用的。

@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);// Try even with null return value. ResponseBodyAdvice could get involved.
        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

上面是序列化时用到的。

当然也可以F7一点一点的debug也会进入到这里。

然后继续:

for (HttpMessageConverter<?> converter : this.messageConverters) {GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?(GenericHttpMessageConverter<?>) converter : null);if (genericConverter != null ?((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :converter.canWrite(valueType, selectedMediaType)) {body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) converter.getClass(),inputMessage, outputMessage);if (body != null) {Object theBody = body;LogFormatUtils.traceDebug(logger, traceOn ->"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter != null) {  genericConverter.write(body, targetType, selectedMediaType, outputMessage);}else {((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);}}else {if (logger.isDebugEnabled()) {logger.debug("Nothing to write: null body");}}return;}}

又走了这样的循环城,上篇中也介绍到了类型的循环,它就是要找到个们的jackson:

org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

下面的步骤太多,我就把调用的堆栈截图出来:

看第一行,又是BeanSerielizer

public final void serialize(Object bean, JsonGenerator gen, SerializerProvider provider)throws IOException{if (_objectIdWriter != null) {gen.setCurrentValue(bean); // [databind#631]_serializeWithObjectId(bean, gen, provider, true);return;}gen.writeStartObject(bean);if (_propertyFilterId != null) {serializeFieldsFiltered(bean, gen, provider);} else {
            serializeFields(bean, gen, provider);
        }gen.writeEndObject();}

开始序列化每个属性:

protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider)throws IOException{final BeanPropertyWriter[] props;if (_filteredProps != null && provider.getActiveView() != null) { props = _filteredProps;} else {props = _props;}int i = 0;try {for (final int len = props.length; i < len; ++i) {BeanPropertyWriter prop = props[i];if (prop != null) { // can have nulls in filtered listprop.serializeAsField(bean, gen, provider);}}if (_anyGetterWriter != null) {_anyGetterWriter.getAndSerialize(bean, gen, provider);}} catch (Exception e) {String name = (i == props.length) ? "[anySetter]" : props[i].getName();wrapAndThrow(provider, e, bean, name);} catch (StackOverflowError e) {// 04-Sep-2009, tatu: Dealing with this is tricky, since we don't have many//   stack frames to spare... just one or two; can't make many calls.// 10-Dec-2015, tatu: and due to above, avoid "from" method, call ctor directly://JsonMappingException mapE = JsonMappingException.from(gen, "Infinite recursion (StackOverflowError)", e);JsonMappingException mapE = new JsonMappingException(gen, "Infinite recursion (StackOverflowError)", e);String name = (i == props.length) ? "[anySetter]" : props[i].getName();mapE.prependPath(new JsonMappingException.Reference(bean, name));throw mapE;}}

public void serializeAsField(Object bean, JsonGenerator gen,SerializerProvider prov) throws Exception {// inlined 'get()'  final Object value = (_accessorMethod == null) ? _field.get(bean): _accessorMethod.invoke(bean, (Object[]) null);// Null handling is bit different, check that firstif (value == null) {if (_nullSerializer != null) {gen.writeFieldName(_name);_nullSerializer.serialize(null, gen, prov);}return;}// then find serializer to use JsonSerializer<Object> ser = _serializer;if (ser == null) {Class<?> cls = value.getClass();PropertySerializerMap m = _dynamicSerializers;ser = m.serializerFor(cls);if (ser == null) {ser = _findAndAddDynamic(m, cls, prov);}}// and then see if we must suppress certain values (default, empty)if (_suppressableValue != null) {if (MARKER_FOR_EMPTY == _suppressableValue) {if (ser.isEmpty(prov, value)) {return;}} else if (_suppressableValue.equals(value)) {return;}}// For non-nulls: simple check for direct cyclesif (value == bean) {// three choices: exception; handled by call; or pass-throughif (_handleSelfReference(bean, gen, prov, ser)) {return;}} gen.writeFieldName(_name);if (_typeSerializer == null) {ser.serialize(value, gen, prov);} else {ser.serializeWithType(value, gen, prov, _typeSerializer);}}

这里用到的序列化的类是com.fasterxml.jackson.databind.ser.std.EnumSerializer,是不是和上一篇很像,其实序列化和反序列化的原理和过程真的很像。

这里由于属性是用的是枚举,但序列化后是汉字:

如果想序列化成数字呢?

我的枚举是这样的:

@Getter
@AllArgsConstructor
//@JsonDeserialize(using = BaseEnumDeserializer.class)
public enum EnumBookingState implements BaseEnum {订购中(1),订购完成(2);//
//@JsonValue
private final int value; }

很简单,只需要在value上中上@JsonValue,但它的原理是什么呢?

同样是上面的截图,但是序列化的工具就是不一样了:

public void serialize(Object bean, JsonGenerator gen, SerializerProvider prov) throws IOException{try {  Object value = _accessor.getValue(bean);if (value == null) {prov.defaultSerializeNull(gen);return;}JsonSerializer<Object> ser = _valueSerializer;if (ser == null) {Class<?> c = value.getClass();/* 10-Mar-2010, tatu: Ideally we would actually separate out type*   serializer from value serializer; but, alas, there's no access*   to serializer factory at this point... */// let's cache it, may be needed soon againser = prov.findTypedValueSerializer(c, true, _property);}ser.serialize(value, gen, prov);} catch (Exception e) {wrapAndThrow(prov, e, bean, _accessor.getName() + "()");}}

为什么打上了标签就用的是JsonValueSerializer?

protected final JsonSerializer<?> findSerializerByAnnotations(SerializerProvider prov, JavaType type, BeanDescription beanDesc)throws JsonMappingException{Class<?> raw = type.getRawClass();// First: JsonSerializable?if (JsonSerializable.class.isAssignableFrom(raw)) {return SerializableSerializer.instance;}// Second: @JsonValue for any typeAnnotatedMember valueAccessor = beanDesc.findJsonValueAccessor();if (valueAccessor != null) {if (prov.canOverrideAccessModifiers()) {ClassUtil.checkAndFixAccess(valueAccessor.getMember(),prov.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));}JsonSerializer<Object> ser = findSerializerFromAnnotation(prov, valueAccessor);return new JsonValueSerializer(valueAccessor, ser);}// No well-known annotations...return null;}

具体的调用调用太多,还是把堆栈信息拿出来:

整个的调用过程与反序列化的过程几乎一样。

下面这个类是一个主要的过程 :

protected JsonSerializer<?> _createSerializer2(SerializerProvider prov,JavaType type, BeanDescription beanDesc, boolean staticTyping)throws JsonMappingException{JsonSerializer<?> ser = null;final SerializationConfig config = prov.getConfig();// Container types differ from non-container types// (note: called method checks for module-provided serializers)if (type.isContainerType()) {if (!staticTyping) {staticTyping = usesStaticTyping(config, beanDesc, null);}// 03-Aug-2012, tatu: As per [databind#40], may require POJO serializer...ser =  buildContainerSerializer(prov, type, beanDesc, staticTyping);// Will return right away, since called method does post-processing:if (ser != null) {return ser;}} else {if (type.isReferenceType()) {ser = findReferenceSerializer(prov, (ReferenceType) type, beanDesc, staticTyping);} else {// Modules may provide serializers of POJO types:for (Serializers serializers : customSerializers()) {ser = serializers.findSerializer(config, type, beanDesc);if (ser != null) {break;}}}// 25-Jun-2015, tatu: Then JsonSerializable, @JsonValue etc. NOTE! Prior to 2.6,//    this call was BEFORE custom serializer lookup, which was wrong.if (ser == null) {ser = findSerializerByAnnotations(prov, type, beanDesc);}}if (ser == null) {// Otherwise, we will check "primary types"; both marker types that// indicate specific handling (JsonSerializable), or main types that have// precedence over container typesser = findSerializerByLookup(type, config, beanDesc, staticTyping);if (ser == null) {ser = findSerializerByPrimaryType(prov, type, beanDesc, staticTyping);if (ser == null) {// And this is where this class comes in: if type is not a// known "primary JDK type", perhaps it's a bean? We can still// get a null, if we can't find a single suitable bean property.ser = findBeanSerializer(prov, type, beanDesc);// Finally: maybe we can still deal with it as an implementation of some basic JDK interface?if (ser == null) {ser = findSerializerByAddonType(config, type, beanDesc, staticTyping);// 18-Sep-2014, tatu: Actually, as per [jackson-databind#539], need to get//   'unknown' serializer assigned earlier, here, so that it gets properly//   post-processedif (ser == null) {ser = prov.getUnknownTypeSerializer(beanDesc.getBeanClass());}}}}}if (ser != null) {// [databind#120]: Allow post-processingif (_factoryConfig.hasSerializerModifiers()) {for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {ser = mod.modifySerializer(config, beanDesc, ser);}}}return ser;}

这个方法名,就告诉我们答案了:findSerializerByAnnotations

转载于:https://www.cnblogs.com/hankuikui/p/11593779.html

spring boot 是如何利用jackson进行序列化的?相关推荐

  1. spring boot 是如何利用jackson进行反序列化的?

    以下面的代码为例: @RestController public class HelloController {@RequestMapping("/")public BillSea ...

  2. Spring Boot框架中使用Jackson的处理总结

    1.前言 通常我们在使用Spring Boot框架时,如果没有特别指定接口的序列化类型,则会使用Spring Boot框架默认集成的Jackson框架进行处理,通过Jackson框架将服务端响应的数据 ...

  3. spring boot java app_利用spring boot创建java app

    利用spring boot创建java app 背景 在使用spring框架开发的过程中,随着功能以及业务逻辑的日益复杂,应用伴随着大量的XML配置和复杂的bean依赖关系,特别是在使用mvc的时候各 ...

  4. Spring Boot 2.0 利用 Spring Security 实现简单的OAuth2.0认证方式1

    0. 前言 之前帐号认证用过自己写的进行匹配,现在要学会使用标准了.准备了解和使用这个OAuth2.0协议. 1. 配置 1.1 配置pom.xml 有些可能会用不到,我把我项目中用到的所有包都贴出来 ...

  5. SpringBoot学习之路:06.Spring Boot替换默认的Jackson

    2019独角兽企业重金招聘Python工程师标准>>> SpringBoot和Springmvc都可以返回接送数据,SpringBoot默认是使用Jackson解析json数据的,个 ...

  6. Spring Boot(四):利用devtools实现热部署,改动代码自动生效

    一.前言 spring-boot-devtools是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去.原理是在发现代码有更改之后,重新启动应用,但是速度比手动停止后 ...

  7. Spring boot使用Rabbitmq注解及消息序列化

    一.三个注解 @EnableRabbit @RabbitListener @RabbitHandler @EnableRabbit @EnableRabbit和@Configuration一起使用,可 ...

  8. Spring Boot jackson配置使用详解

    Spring Boot系列-json框架jackson配置详解 T1 - 前言 目前Java最常见的3中JSON操作框架分别为Gson.Jackson.FastJson,该篇文章主要讲解jackson ...

  9. Spring Boot 利用WebUploader进行文件上传

    Web Uploader WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件.在现代的浏览器里面能充分发挥HTML5的优势 ...

最新文章

  1. MATLAB实例路径与安装路径
  2. 题解 P1918【 保龄球 】python和C++
  3. 职场警示录:栽在邮件上的N种死法
  4. 数据可用不可见!揭秘蚂蚁区块链摩斯安全计算平台
  5. 计算机的配件知识,一台电脑需要多少配件组成,硬件知识介绍
  6. 多线程 - 你知道线程栈吗
  7. mac android通知中心,少数派一周快读:iOS 8 输入法大比拼,升级 Mac 新系统的 6 项准备,如何保持 Android 通知栏整洁...
  8. matlab计算复活节概率,复活节日期的计算方法
  9. Sersync实时备份服务部署实践
  10. java的poi技术读取Excel[2003-2007,2010]
  11. Linux 网络编程——UDP编程
  12. android开发中的grid控制
  13. 拓端tecdat|R语言有限混合模型聚类FMM、广义线性回归模型GLM混合应用分析威士忌市场和研究专利申请、支出数据
  14. 计算机操作系统(第四版)课后习题答案(完整版)
  15. ubuntu中颜色拾取器的安装以及16进制ARGB值在线转颜色
  16. CNN实现手写数字识别
  17. 中关村买手机上当案例
  18. Chrome 火焰图
  19. 苹果微软小米华为,创新四重奏?
  20. 100000以内的质数表

热门文章

  1. 【kibana】 kibana报错内存溢出 CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
  2. 中国蓝莓种植深加工市场分析及投资前景预测报告2022-2028年
  3. 2022年9月高频前端面试题总结
  4. 直播回顾 | 子芽CCF TF:云原生场景下软件供应链风险治理技术浅谈
  5. 基于单片机的智能门锁设计
  6. 基于ANFIS的股票价格预测附Python代码
  7. 刷百度相关搜索就用【胖虎图图-互动点击系统】
  8. vue重置data数据 神器之Object.assign()
  9. Spoken English-口语-音节介绍
  10. 英语二大作文-贫困人口问题