当使用 Spring MVC for REST 时,如何让 Jackson 漂亮地打印渲染的 JSON?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6541757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When using Spring MVC for REST, how do you enable Hymanson to pretty-print rendered JSON?
提问by Les Hazlewood
While developing REST services using Spring MVC, I would like render JSON 'pretty printed' in development but normal (reduced whitespace) in production.
在使用 Spring MVC 开发 REST 服务时,我希望在开发中呈现 JSON '漂亮打印',但在生产中呈现正常(减少空格)。
采纳答案by user4061342
If you are using Spring Boot 1.2 or later the simple solution is to add
如果您使用的是 Spring Boot 1.2 或更高版本,简单的解决方案是添加
spring.Hymanson.serialization.INDENT_OUTPUT=true
to the application.propertiesfile. This assumes that you are using Hymanson for serialization.
到application.properties文件。这假设您使用 Hymanson 进行序列化。
If you are using an earlier version of Spring Boot then you can add
如果您使用的是较早版本的 Spring Boot,则可以添加
http.mappers.json-pretty-print=true
This solution still works with Spring Boot 1.2 but it is deprecatedand will eventually be removed entirely. You will get a deprecation warning in the log at startup time.
这个解决方案仍然适用于 Spring Boot 1.2,但它已被弃用,最终将被完全删除。您将在启动时在日志中收到弃用警告。
(tested using spring-boot-starter-web)
(测试使用spring-boot-starter-web)
回答by Les Hazlewood
I had an answer when I posted this question, but I thought I'd post it anyway in case there are better alternative solutions. Here was my experience:
当我发布这个问题时,我有一个答案,但我想我还是会发布它,以防有更好的替代解决方案。这是我的经验:
First thing's first. The MappingHymansonHttpMessageConverterexpects you to inject a Hymanson ObjectMapperinstance and perform Hymanson configuration on that instance (and not through a Spring class).
第一件事是第一件事。该MappingHymansonHttpMessageConverter希望你注入Hyman逊ObjectMapper实例,该实例执行Hyman逊的配置(而不是通过Spring类)。
I thought it would be as easy as doing this:
我认为这会像这样做一样简单:
Create an ObjectMapperFactoryBeanimplementation that allows me to customize the ObjectMapperinstance that can be injected into the MappingHymansonHttpMessageConverter. For example:
创建一个ObjectMapperFactoryBean实现,允许我自定义ObjectMapper可以注入到MappingHymansonHttpMessageConverter. 例如:
<bean id="HymansonHttpMessageConverter" class="org.springframework.http.converter.json.MappingHymansonHttpMessageConverter">
<property name="objectMapper">
<bean class="com.foo.my.ObjectMapperFactoryBean">
<property name="prettyPrint" value="${json.prettyPrint}"/>
</bean>
</property>
</bean>
And then, in my ObjectMapperFactoryBeanimplementation, I could do this (as has been documented as a solution elsewhere on SO):
然后,在我的ObjectMapperFactoryBean实现中,我可以这样做(正如其他地方的解决方案所记录的那样):
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, isPrettyPrint());
return mapper;
But it didn't work. And trying to figure out why is a nightmare. It is a major test of patience to figure Hymanson out. Looking at its source code only confuses you further as it uses outdated and obtuse forms of configuration (integer bitmasks for turning on/off features? Are you kidding me?)
但它没有用。并试图弄清楚为什么是一场噩梦。找出Hyman逊是对耐心的重大考验。查看它的源代码只会让你更加困惑,因为它使用过时和迟钝的配置形式(用于打开/关闭功能的整数位掩码?你在开玩笑吗?)
I essentially had to re-write Spring's MappingHymansonHttpMessageConverterfrom scratch, and override its writeInternalimplementation to be the following:
我基本上不得不MappingHymansonHttpMessageConverter从头开始重写Spring ,并将其writeInternal实现覆盖如下:
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType());
JsonGenerator jsonGenerator =
getObjectMapper().getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
try {
if (this.prefixJson) {
jsonGenerator.writeRaw("{} && ");
}
if (isPrettyPrint()) {
jsonGenerator.useDefaultPrettyPrinter();
}
getObjectMapper().writeValue(jsonGenerator, o);
}
catch (JsonGenerationException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
}
}
The only thing I added to the existing implementation is the following block:
我添加到现有实现中的唯一内容是以下块:
if (isPrettyPrint()) {
jsonGenerator.useDefaultPrettyPrinter();
}
isPrettyPrint()is just a JavaBeans compatible getter w/ matching setter that I added to my MappingHymansonHttpMessageConvertersubclass.
isPrettyPrint()只是我添加到我的MappingHymansonHttpMessageConverter子类中的带有匹配 setter 的 JavaBeans 兼容 getter 。
Only after jumping through these hoops was I able to turn on or off pretty printing based on my ${json.prettyPrint}value (that is set as a property depending on how the app is deployed).
只有在跳过这些箍之后,我才能根据我的${json.prettyPrint}值打开或关闭漂亮的打印(根据应用程序的部署方式将其设置为属性)。
I hope this helps someone out in the future!
我希望这对将来的人有所帮助!
回答by Swato
When you are using Hymanson 2.0.0, you can do it in a way Les wanted to. I currently use RC3 and the configuration seems to be working as expected.
当您使用 Hymanson 2.0.0 时,您可以按照 Les 想要的方式进行操作。我目前使用 RC3,配置似乎按预期工作。
ObjectMapper HymansonMapper = new ObjectMapper();
HymansonMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
translates
翻译
{"foo":"foo","bar":{"field1":"field1","field2":"field2"}}
into
进入
{
"foo" : "foo",
"bar" : {
"field1" : "field1",
"field2" : "field2"
}
}
回答by MattJ
Might I suggest this approach, it is valid with Spring 4.0.x and possibly older versions.
我是否可以建议这种方法,它适用于 Spring 4.0.x 和可能的旧版本。
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.databind.SerializationFeature;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Bean
public MappingHymanson2HttpMessageConverter mappingHymanson2HttpMessageConverter() {
MappingHymanson2HttpMessageConverter mappingHymanson2HttpMessageConverter = new MappingHymanson2HttpMessageConverter();
mappingHymanson2HttpMessageConverter.setObjectMapper(objectMapper());
return mappingHymanson2HttpMessageConverter;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objMapper = new ObjectMapper();
objMapper.enable(SerializationFeature.INDENT_OUTPUT);
return objMapper;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
converters.add(mappingHymanson2HttpMessageConverter());
}
}
Thanks to Willie Wheeler for the solution: Willie Wheeler's Spring blog
感谢 Willie Wheeler 的解决方案:Willie Wheeler 的 Spring 博客
回答by Programmer Bruce
How do I make Hymanson pretty-print the JSON content it generates?
我如何让 Hymanson 漂亮地打印它生成的 JSON 内容?
Here's a simple example:
这是一个简单的例子:
Original JSON Input:
原始 JSON 输入:
{"one":"AAA","two":["BBB","CCC"],"three":{"four":"DDD","five":["EEE","FFF"]}}
Foo.java:
Foo.java:
import java.io.FileReader;
import org.codehaus.Hymanson.map.ObjectMapper;
import org.codehaus.Hymanson.map.ObjectWriter;
public class Foo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
MyClass myObject = mapper.readValue(new FileReader("input.json"), MyClass.class);
// this is Hymanson 1.x API only:
ObjectWriter writer = mapper.defaultPrettyPrintingWriter();
// ***IMPORTANT!!!*** for Hymanson 2.x use the line below instead of the one above:
// ObjectWriter writer = mapper.writer().withDefaultPrettyPrinter();
System.out.println(writer.writeValueAsString(myObject));
}
}
class MyClass
{
String one;
String[] two;
MyOtherClass three;
public String getOne() {return one;}
void setOne(String one) {this.one = one;}
public String[] getTwo() {return two;}
void setTwo(String[] two) {this.two = two;}
public MyOtherClass getThree() {return three;}
void setThree(MyOtherClass three) {this.three = three;}
}
class MyOtherClass
{
String four;
String[] five;
public String getFour() {return four;}
void setFour(String four) {this.four = four;}
public String[] getFive() {return five;}
void setFive(String[] five) {this.five = five;}
}
Output:
输出:
{
"one" : "AAA",
"two" : [ "BBB", "CCC" ],
"three" : {
"four" : "DDD",
"five" : [ "EEE", "FFF" ]
}
}
If this approach doesn't exactly fit your needs, if you search the API docs v1.8.1for "pretty", it'll turn up the relevant components available. If you use API version 2.x then look instead at the newer API 2.1.0 docs.
如果这种方法不能完全满足您的需求,如果您在 API 文档 v1.8.1 中搜索“漂亮”,它会显示可用的相关组件。如果您使用 API 2.x 版,请查看较新的 API 2.1.0 文档。
回答by Ben Asmussen
Pretty print will be enable by adding and configure the MappingHymanson2HttpMessageConverterconverter. Disable prettyprint within production environment.
通过添加和配置MappingHymanson2HttpMessageConverter转换器,将启用漂亮的打印。在生产环境中禁用prettyprint。
Message converter configuration
消息转换器配置
<mvc:annotation-driven>
<mvc:message-converters>
<bean id="HymansonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter">
<property name="prettyPrint" value="${json.prettyPrint}" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
回答by davidwillianx
Based on baeldungthis could be a nice idea using java 8:
基于baeldung这可能是一个使用 java 8 的好主意:
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
Optional<HttpMessageConverter<?>> converterFound;
converterFound = converters.stream().filter(c -> c instanceof AbstractHymanson2HttpMessageConverter).findFirst();
if (converterFound.isPresent()) {
final AbstractHymanson2HttpMessageConverter converter;
converter = (AbstractHymanson2HttpMessageConverter) converterFound.get();
converter.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
converter.getObjectMapper().enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
}
回答by kdonald
Hymanson 2 has a nicer API, agreed, but it won't resolve this problem in a Spring MVC environment given Spring MVC uses ObjectMapper#writeValue(JsonGenerator, Object) to write objects out as JSON. This writeValue variant does not apply ObjectMapper serialization features such as INDENT_OUTPUT in either Hymanson 1.x or 2.0.
Hymanson 2 有一个更好的 API,同意,但它不会在 Spring MVC 环境中解决这个问题,因为 Spring MVC 使用 ObjectMapper#writeValue(JsonGenerator, Object) 将对象写出为 JSON。此 writeValue 变体不应用 ObjectMapper 序列化功能,例如 Hymanson 1.x 或 2.0 中的 INDENT_OUTPUT。
I do think this is somewhat confusing. Since we use the ObjectMapper to construct JsonGenerators, I'd expect returned generators to be initialized based on configured ObjectMapper settings. I reported this as a issue against Hymanson 2.0 here: https://github.com/FasterXML/Hymanson-databind/issues/12.
我确实认为这有点令人困惑。由于我们使用 ObjectMapper 来构造 JsonGenerators,我希望返回的生成器根据配置的 ObjectMapper 设置进行初始化。我在此处将其报告为针对 Hymanson 2.0 的问题:https: //github.com/FasterXML/Hymanson-databind/issues/12。
Les's suggestion of calling JsonGenerator#useDefaultPrettyPrinter based on the value of a prettyPrint flag is about the best we can do at the moment. I've gone ahead and created a Hymanson2 HttpMessageConverter that does this based on the enabled status of the INDENT_OUTPUT SerializationFeature: https://gist.github.com/2423129.
Les 的建议是基于一个 prettyPrint 标志的值调用 JsonGenerator#useDefaultPrettyPrinter 是我们目前能做的最好的事情。我已经创建了一个 Hymanson2 HttpMessageConverter,它根据 INDENT_OUTPUT SerializationFeature 的启用状态执行此操作:https://gist.github.com/2423129 。
回答by user977505
I had trouble getting the custom MappingHymansonHttpMessageConverter to work as suggested above but I was finally able to get it to work after struggling w/ the configuration. From the code stand point I did exactly what was mentioned above but I had to add the following configuration to my springapp-servlet.xml to get it to work.
我无法按照上面的建议让自定义 MappingHymansonHttpMessageConverter 工作,但我终于能够在配置上挣扎后让它工作。从代码的角度来看,我完全按照上面提到的去做,但是我必须将以下配置添加到 springapp-servlet.xml 中才能使其工作。
I hope this helps others who are looking to implement the same.
我希望这可以帮助其他希望实现相同功能的人。
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter" class="com.xxx.xxx.xxx.common.PrettyPrintMappingHymansonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
<property name="prettyPrint" value="true" />
</bean>
回答by duffymo
I would make that a rendering issue, not the concern of the REST service.
我会将其视为渲染问题,而不是 REST 服务的关注点。
Who's doing the rendering? Let that component format the JSON. Maybe it can be two URLs - one for production and another for development.
谁在做渲染?让该组件格式化 JSON。也许它可以是两个 URL——一个用于生产,另一个用于开发。

