Demand background

Requirements: In the microservice system built by SpringMVC, the database stores the date as a Long timestamp. The front-end used the default Long time before, but now the front-end framework changes to require the back-end to respond to the data, the Long time automatically changes to the standard time format (YYYY-MM-DD HH: MM: SS).

SQL > create table createTime (createTime); SQL > create table createTime (createTime); SQL > create table createTime (createTime);

Requirement 2: If the front-end framework does not handle this problem, when the JSON request received by the back-end is deserialized into an object, the value of String type will appear with Spaces before and after. Therefore, a unified processing method is needed. Execute the trim method on the received String attribute.

The solution

The default JSON framework for SpringMVC is Jackson, and you can also use FastJSON.

Jackson framework

Custom serialization

If your project uses the Jackson framework for JSON serialization, the recommended solution is to use the @jsonSerialize annotation, as shown in the following code:

@JsonSerialize(using = CustomDateSerializer.class)  
private Long createTime;

@JsonSerialize(using = CustomDateSerializer.class)  
private Long updateTime;
Copy the code

The following is an example of the CustomDateSerializer class:

public class CustomDateSerializer extends JsonSerializer<Long> {

	@Override
	public void serialize(Long aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = newDate(aLong); jsonGenerator.writeString(sdf.format(date)); }}Copy the code

The benefits of such a scheme are as follows:

  1. Custom implementation classes can be reused
  2. CreateTime and updateTime are not limited to fields that need to be converted

The disadvantage is that all the fields that need to be converted need to be annotated, which is a bit of work

Of course, there are other unified treatment schemes, which are not described here.

Custom deserialization

It is also convenient to implement custom serialization on the Jackson framework by inheriting the SimpleModule class:

@Component
public class StringTrimModule extends SimpleModule {

    public StringTrimModule(a) {
        addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
            @Override
            public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
                String value = jsonParser.getValueAsString();
                if (StringUtils.isEmpty(value)) {
                     return value;
                }
                returnvalue.trim(); }}); }}Copy the code

Fastjson framework

If this dependency appears in the project:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.262.</version>
</dependency>
Copy the code

Jackson @JsonSerialize does not have a trigger entry in Fastjson.

Custom serialization

Accordingly, there are configuration classes for fastjson, as shown in the following example:

/** * Uniform output is using fastJson **@return* /
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters(a) {
	//convert Convert message object
	FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

	// Handle Chinese garbled characters
	List<MediaType> fastMediaTypes = new ArrayList<>();
	fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
	fastConverter.setSupportedMediaTypes(fastMediaTypes);

	// Whether to format the returned JSON data
	FastJsonConfig fastJsonConfig = new FastJsonConfig();
	fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
	// Add value conversion processing for the specified field
    fastJsonConfig.setSerializeFilters(new CustomerDateFilter());
	// FastJson disables autoTypeSupport
	fastJsonConfig.getParserConfig().setAutoTypeSupport(false);
	fastConverter.setFastJsonConfig(fastJsonConfig);

	return new HttpMessageConverters(fastConverter);
}
Copy the code

Here you need to add fastjson handling of the field values (the code above has added this line), as in

// Add value conversion processing for the specified field
fastJsonConfig.setSerializeFilters(new CustomerDateFilter());
Copy the code

CustomerDateFilter is a self-implemented class with the following code:

public class CustomerDateFilter implements ValueFilter {

	@Override
	public Object process(Object object, String name, Object value) {
		if (FieldConstants.CREATE_TIME.equalsIgnoreCase(name) ||  FieldConstants.UPDATE_TIME.equalsIgnoreCase(name)) {
			// The property name is createTime, updateTime for conversion
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));

			if(value instanceof Long) {
				Long time = (Long) value;
				Date date = new Date(time);
				return sdf.format(date);
			} else {
				returnvalue; }}returnvalue; }}Copy the code

This makes it convenient to treat createTime and updateTime fields that occur in all response objects, whether they are lists or individual objects. The disadvantage is that in addition to the field, if the whole system is not unified, you need to deal with separately.

SerializeFilter Custom serialization

SerializeFilter supports the following extended programming interfaces for customized serialization, which can be extended as required:

  • PropertyPreFilter: Determines serialization based on the PropertyName.
  • PropertyFilter: Determines serialization based on PropertyName and PropertyValue.
  • NameFilter: Changes the Key. If the Key needs to be changed, the value returned by process can be changed.
  • ValueFilter: modifies a Value.
  • BeforeFilter: Add content first when serializing;
  • AfterFilter: Adding content at the end of serialization;
Custom deserialization

FastJson provides serialization filters to implement custom serialization transformations, but does not provide deserialization filters to implement corresponding functions.

Solution: @jsonfield annotation

Back to the JSON String value trim operation, the official website supports @jsonField annotation attribute setting (fastJson version 1.2.36 or later) :

@JSONField(format="trim")
private String name;
Copy the code

When the JSON message is deserialized, the name attribute of the entity is automatically processed by the trim method.

This scheme only adds annotations one by one, which is a lot of work.

Solution: Implement the ObjectDeserializer interface

The ObjectDeserializer interface is used to implement custom deserialization. It works with the global Settings of ParserConfig to achieve the desired effect. The StringTrimDeserializer class is jointly created to handle String:

/ * * *@title: StringTrimDeserializer
 * @description: Trim all String contents */
public class StringTrimDeserializer implements ObjectDeserializer {

	@Override
	public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
		// The logic for deserializing a JSON String is more complicated. On top of StringCodec, call trim on the result
		Object obj = StringCodec.instance.deserialze(parser, type, fieldName);
		if (obj instanceof String) {
			String str = (String) obj;
			return (T) str.trim();
		}
		return (T) obj;
	}

	@Override
	public int getFastMatchToken(a) {
		returnJSONToken.LITERAL_STRING; }}Copy the code

Accordingly, in HttpMessageConverters fastJsonHttpMessageConverters method and increase the String class deserialization Settings:

// Set the global deserialization rule for String: complete trim automatically
ParserConfig.getGlobalInstance().putDeserializer(String.class, new StringTrimDeserializer());
Copy the code

Parser.getlexer ().stringval () and trim instead of calling the stringCodec.instance method.

StringCodec is fastJson’s default String deserialization logic class. It handles the following types: String, StringBuffer, StringBuilder, etc., as well as a variety of collections and array structures. In order to deserialize String text, the implementation logic and scenarios are complicated. This time, we need to perform trim on the String, but we need to leave the complicated logic to StringCodec.

summary

Today it is record Json custom serialization and deserialization of practices, began to confirm before which is used in the engineering framework, can appear otherwise added @ JsonSerialize annotations, make the most of no effect, turn head a see framework is fastjson, no trigger entrance, of course, can not get the desired effect, A little advice. I hope it helps.