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