SpringBoot sets the return field of Json to be non empty

preface

You may have encountered the following problems. In the project development, the back-end returns data in Json format to the front-end, but for fields with empty data, null may appear, which makes the front-end students very painful. So they think, for those null fields, can the back-end return String data to empty String and int data to 0, Collection and array return [], how convenient it is! OK, since this meets their requirements, this paper uses the Json converter provided by Spring to process the data returned to the front end, as shown below.

1, Write Json data converter

/**
 * @Author yangs
 * @Date: January 20, 2022
 * @Describe json data converter
 */
public class JacksonHttpMessageConverter extends MappingJackson2HttpMessageConverter {

    /**
     * Handle null values of array types
     */
    public class NullArrayJsonSerializer extends JsonSerializer<Object> {

        @Override
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            if (value == null) {
                jgen.writeStartArray();
                jgen.writeEndArray();
            }
        }
    }


    /**
     * Handle null values of string type
     */
    public class NullStringJsonSerializer extends JsonSerializer<Object> {

        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
            jsonGenerator.writeString(StringUtils.EMPTY);
        }
    }

    /**
     * Handling null values of numeric types
     */
    public class NullNumberJsonSerializer extends JsonSerializer<Object> {

        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
            jsonGenerator.writeNumber(0);
        }
    }

    /**
     * Handles null values of Boolean types
     */
    public class NullBooleanJsonSerializer extends JsonSerializer<Object> {

        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
            jsonGenerator.writeBoolean(false);
        }
    }


    public class MyBeanSerializerModifier extends BeanSerializerModifier {

        @Override
        public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
            //Loop all beanpropertywriters
            for (Object beanProperty : beanProperties) {
                BeanPropertyWriter writer = (BeanPropertyWriter) beanProperty;
                //Judge the type of field. If it is array, list, set, register nullSerializer
                if (isArrayType(writer)) {
                    //Register the writer with its own nullSerializer
                    writer.assignNullSerializer(new NullArrayJsonSerializer());
                } else if (isNumberType(writer)) {
                    writer.assignNullSerializer(new NullNumberJsonSerializer());
                } else if (isBooleanType(writer)) {
                    writer.assignNullSerializer(new NullBooleanJsonSerializer());
                } else if (isStringType(writer)) {
                    writer.assignNullSerializer(new NullStringJsonSerializer());
                }
            }
            return beanProperties;
        }

        /**
         * Is it an array
         */
        private boolean isArrayType(BeanPropertyWriter writer) {
            Class<?> clazz = writer.getType().getRawClass();
            return clazz.isArray() || Collection.class.isAssignableFrom(clazz);
        }

        /**
         * Is it a string
         */
        private boolean isStringType(BeanPropertyWriter writer) {
            Class<?> clazz = writer.getType().getRawClass();
            return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
        }


        /**
         * Is it int
         */
        private boolean isNumberType(BeanPropertyWriter writer) {
            Class<?> clazz = writer.getType().getRawClass();
            return Number.class.isAssignableFrom(clazz);
        }

        /**
         * Is it a boolean
         */
        private boolean isBooleanType(BeanPropertyWriter writer) {
            Class<?> clazz = writer.getType().getRawClass();
            return clazz.equals(Boolean.class);
        }

    }

    public JacksonHttpMessageConverter() {
        getObjectMapper().setSerializerFactory(getObjectMapper().getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));
    }

}

2, Write MVC configuration file

Next, we will write an MVC configuration class, inherit the WebMvcConfigurationSupport class, and rewrite the configureMessageConverters() method. In this method, we will load the Json conversion tool defined above to realize the functions we want.

/**
 * @Author yangs
 * @Date: January 20, 2022
 * @Describes the configuration class of MVC
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    // File mapping path
    @Value("${fileMappingPath}")
    private String fileMappingPath;

    /**
     * @Author yangs
     * @Date: January 20, 2022
     * @Describes the json format converter returned to the front end
     */
    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        converters.add(new JacksonHttpMessageConverter());
    }
    
}

So far, we have implemented the desired functions, converting null of String type to '', null of Integer type to 0, and empty collection and array to []. However, after inheriting WebMvcConfigurationSupport, there may be some pitfalls, such as static resource acquisition. Keep looking down. Maybe you can prevent burying mines.

3, Lightning warning

Inheriting the WebMvcConfigurationSupport class will make the application The static resource mapping configured in YML fails. If you configure the following code in the configuration file, you must be vigilant:

spring:
  mvc:
    static-path-pattern: /image/**
  resources:
    static-locations: file:E:/picture/

When we inherit the WebMvcConfigurationSupport class, the static resource mapping of the configuration file will fail, so we need another solution. Just override the addResourceHandlers() method in the subclass of WebMvcConfigurationSupport, as shown below:

/**
 * @Author yangs
 * @Date: January 20, 2022
 * @Describes the configuration class of MVC
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * @Author yangs
     * @Date: January 20, 2022
     * @Describes the json format converter returned to the front end
     */
    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        converters.add(new JacksonHttpMessageConverter());
    }

    // File mapping path
    @Value("${fileMappingPath}")
    private String fileMappingPath;

    /**
     * @Author yangs
     * @Date: January 20, 2022
     * @Describes configuring static resource access paths
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        //Get static resources through image
        registry.addResourceHandler("/image/**").addResourceLocations(fileMappingPath);
    }
}

You can also check out my other article on how to access local static resources in SpringBoot, SpringBoot accesses local static resources.

Keywords: Front-end JSON Spring Boot

Added by Shuriken1 on Mon, 24 Jan 2022 15:19:01 +0200