spring boot 是如何利用jackson进行序列化的?
接上一篇: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; }
上面是反序列化时用的。
@Override public 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 list prop.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 first if (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 cycles if (value == bean) { // three choices: exception; handled by call; or pass-through if (_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 again ser = 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 type AnnotatedMember 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 types ser = 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-processed if (ser == null) { ser = prov.getUnknownTypeSerializer(beanDesc.getBeanClass()); } } } } } if (ser != null) { // [databind#120]: Allow post-processing if (_factoryConfig.hasSerializerModifiers()) { for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) { ser = mod.modifySerializer(config, beanDesc, ser); } } } return ser; }
这个方法名,就告诉我们答案了:findSerializerByAnnotations