Connect one: the Spring is how to use the Boot jackson anti serialized?
@RestController public class HelloController { @RequestMapping("/") public BillSearch hello(@RequestBody BillSearch search) { return search; } }
The search is how to return the json serialization?
Previous Speaking RequestResponseBodyMethodProcessor This class is very important in json serialization and de-serialization are in:
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; }
The above is the deserialization.
@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); }
The above is used when serialized.
F7 course, you can also enter a little bit of debug here.
Then continue:
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; } }
And went this cycle city, the article also introduced to the types of loops, it is to find one who jackson:
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
The following steps are too many, I put out the call stack screenshots:
Look at the first line, but also 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(); }
Start sequence of each property:
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); } }
Here used to serialize the class is com.fasterxml.jackson.databind.ser.std.EnumSerializer, is not a like, and in fact the serialization and de-serialization of the principles and processes really like.
Since this attribute is used to enumerate, but the sequence of characters is:
If you want to serialize figures?
I enumeration is this:
@Getter @AllArgsConstructor // @JsonDeserialize (= the using BaseEnumDeserializer.class) public enum EnumBookingState the implements BaseEnum { Usually in ( 1 ), order completion ( 2 ); //
//@JsonValue
private final int value; }
Very simple, just in the @JsonValue on the value, but it's the principle of what is it?
The same is the screenshot above, but the sequence of the tool is not the same:
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() + "()"); } }
Why it is marked on the label using a 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; }
Specific call to call too much, or the stack information out:
The whole process of calling and anti-serialization process is almost the same.
The following class is a primary process:
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; }
This method name, just tell us the answer: findSerializerByAnnotations