如何在控制器响应时间上设置Json PropertyNamingStrategy

时间:2019-07-17 17:47:21

标签: java json spring-boot jackson naming-conventions

我有一个REST控制器,它返回一个Object。我想在控制器动作响应时设置PropertyNamingStrategy。例如,基于谁调用此控制器,我想通过发送Camel case命名约定进行响应,而在另一种情况下,则返回Snake case命名样式。我可以在控制器操作中使用对象映射器,但是只会返回String类型。我仍然想要我的Object类型,但是使用不同的命名约定。有什么建议吗?

我正在使用Springboot 2.x

2 个答案:

答案 0 :(得分:0)

我想出了解决这个问题的方法。我将命名策略扩展为:

 public class GetSnakeCaseSetCamelCaseNamingStrategy
    extends PropertyNamingStrategy.PropertyNamingStrategyBase {

  @Override
  public String translate(String propertyName) {
    return propertyName;
  }

  @Override
  public String nameForGetterMethod(
      MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
    return PropertyNamingStrategy.SNAKE_CASE.nameForGetterMethod(config, method, defaultName);
  }

  @Override
  public String nameForSetterMethod(
      MapperConfig<?> config, AnnotatedMethod method, String defaultName) {

    return PropertyNamingStrategy.UPPER_CAMEL_CASE.nameForSetterMethod(config, method, defaultName);
  }
}

然后用我自己的命名策略为我的Pojo注释,并且有效!

答案 1 :(得分:0)

如果您的rest控制器返回一个POJO,并且需要使用不同的命名策略将POJO转换为JSON,例如,根据给定类型的用户,将SNAKE_CASE转换为JSON,将其他类型的用户的CAMEL_CASE转换为JSON,则您需要创建自己的HttpMessageConverter并在Spring中注册它。

  1. 您的自定义HttpMessageConverter如下所示:-
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.util.TypeUtils;

import java.io.IOException;
import java.lang.reflect.Type;

class CustomJackson2HttpMessageConverter
        extends MappingJackson2HttpMessageConverter {

    private static final ObjectMapper snakeCaseObjectMapper = new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

    ObjectMapper defaultObjectMapper = new ObjectMapper();


    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        MediaType contentType = outputMessage.getHeaders().getContentType();
        JsonEncoding encoding = getJsonEncoding(contentType);
        //Note:- Get the appropriate ObjectMapper and use them to write Object to Json string accordingly
        ObjectMapper objectMapper = getObjectMapper(outputMessage);
        JsonGenerator generator = objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
        try {
            writePrefix(generator, object);

            Class<?> serializationView = null;
            FilterProvider filters = null;
            Object value = object;
            JavaType javaType = null;
            if (object instanceof MappingJacksonValue) {
                MappingJacksonValue container = (MappingJacksonValue) object;
                value = container.getValue();
                serializationView = container.getSerializationView();
                filters = container.getFilters();
            }
            if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
                javaType = getJavaType(type, null);
            }
            ObjectWriter objectWriter;
            if (serializationView != null) {
                objectWriter = objectMapper.writerWithView(serializationView);
            } else if (filters != null) {
                objectWriter = objectMapper.writer(filters);
            } else {
                objectWriter = objectMapper.writer();
            }
            if (javaType != null && javaType.isContainerType()) {
                objectWriter = objectWriter.forType(javaType);
            }
            SerializationConfig config = objectWriter.getConfig();
            if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&
                    config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
                objectWriter = objectWriter.with(this.ssePrettyPrinter);
            }
            objectWriter.writeValue(generator, value);

            writeSuffix(generator, object);
            generator.flush();

        } catch (InvalidDefinitionException ex) {
            throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
        } catch (JsonProcessingException ex) {
            throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
        }
    }

    ObjectMapper getObjectMapper(HttpOutputMessage outputMessage) {
        HttpHeaders responseHeaders = outputMessage.getHeaders();
        /** TODO:- Check in responseHeaders if it is a specific user demanding
         * response with PropertyNamingStrategy as PropertyNamingStrategy.SNAKE_CASE
         * For eg:- you can have a header with name- jsonNamingStrategy=SNAKE_CASE or any default value or empty
         * Based on jsonNamingStrategy you can decide if user wants response in SnakeCase or default one
         * Return appropriately based on your check. For now returning snakeCaseObjectMapper
         **/
        return snakeCaseObjectMapper;
    }
}
  1. 并且您需要使用Spring将您的CustomJackson2HttpMessageConverter注册为:-
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@EnableWebMvc
@Configuration
class WebConfig implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        final MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter = new CustomJackson2HttpMessageConverter();
        //Replace the default MappingJackson2HttpMessageConverter with the CustomJackson2HttpMessageConverter
        converters.replaceAll(it -> it instanceof MappingJackson2HttpMessageConverter ? customJackson2HttpMessageConverter : it);
        if (!converters.contains(customJackson2HttpMessageConverter)) {
            converters.add(customJackson2HttpMessageConverter);
        }
    }
}
  1. 类似地,如果要处理要使用与POJO不同的命名策略来解析JSON的情况,则可以重写CustomJackson2HttpMessageConverter的方法readInternal()。