bot*_*que 6 json jersey jackson
我有一个基于 Jersey (1.x) 的 REST 服务。它使用 Jackson 2.4.4 来生成 JSON 响应。我需要在响应末尾添加一个换行符(cURL 用户抱怨响应中没有换行符)。我正在使用 Jersey 漂亮打印功能 ( SerializationFeature.INDENT_OUTPUT)。
当前的: {\n "prop" : "value"\n}
通缉: {\n "prop" : "value"\n}\n
我尝试使用自定义序列化程序。我\n只需要在根对象的末尾添加。序列化程序是按数据类型定义的,这意味着,如果此类类的实例嵌套在响应中,我将\n处于 JSON 的中间。
我想到了子类化com.fasterxml.jackson.core.JsonGenerator.java,覆盖close() 我要添加的地方writeRaw('\n'),但这感觉很hacky。
另一个想法是添加 Servlet 过滤器,该过滤器将重写来自 Jersey 过滤器的响应,添加\n并将 contentLenght 增加 1。似乎不仅 hacky,而且效率低下。
我也可以放弃 Jersey 来处理内容的序列化并 do ObjectMapper.writeValue() + "\n",但这对我的代码来说非常具有侵入性(需要更改很多地方)。
该问题的干净解决方案是什么?
我发现这些线程解决了同样的问题,但没有一个提供解决方案:
更新
最后,我选择了@arachnid 的解决方案NewlineAddingPrettyPrinter(也将 Jackson 版本提高到 2.6.2)。遗憾的是,Jaskson 作为JAX-RS Json 提供程序并不能开箱即用。改变PrettyPrinter在ObjectMapper没有得到传播到JsonGenerator(见这里为什么)。为了使它工作,我必须添加ResponseFilterwhich added ObjectWriterModifier(现在我可以根据输入参数轻松地在漂亮打印和最小之间切换):
@Provider
public class PrettyPrintFilter extends BaseResponseFilter {
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
ObjectWriterInjector.set(new PrettyPrintToggler(true));
return response;
}
final class PrettyPrintToggler extends ObjectWriterModifier {
private static final PrettyPrinter NO_PRETTY_PRINT = new MinimalPrettyPrinter();
private final boolean usePrettyPrint;
public PrettyPrintToggler(boolean usePrettyPrint) {
this.usePrettyPrint = usePrettyPrint;
}
@Override
public ObjectWriter modify(EndpointConfigBase<?> endpoint, MultivaluedMap<String, Object> responseHeaders,
Object valueToWrite, ObjectWriter w, JsonGenerator g) throws IOException {
if (usePrettyPrint) g.setPrettyPrinter(new NewlineAddingPrettyPrinter());
else g.setPrettyPrinter(NO_PRETTY_PRINT);
return w;
}
}
}
Run Code Online (Sandbox Code Playgroud)
事实上,结束了(不继承)JsonGenerator是不是太糟糕:
public static final class NewlineAddingJsonFactory extends JsonFactory {
@Override
protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException {
return new NewlineAddingJsonGenerator(super._createGenerator(out, ctxt));
}
@Override
protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) throws IOException {
return new NewlineAddingJsonGenerator(super._createUTF8Generator(out, ctxt));
}
}
public static final class NewlineAddingJsonGenerator extends JsonGenerator {
private final JsonGenerator underlying;
private int depth = 0;
public NewlineAddingJsonGenerator(JsonGenerator underlying) {
this.underlying = underlying;
}
@Override
public void writeStartObject() throws IOException {
underlying.writeStartObject();
++depth;
}
@Override
public void writeEndObject() throws IOException {
underlying.writeEndObject();
if (--depth == 0) {
underlying.writeRaw('\n');
}
}
// ... and delegate all the other methods of JsonGenerator (CGLIB can hide this if you put in some time)
}
@Test
public void append_newline_after_end_of_json() throws Exception {
ObjectWriter writer = new ObjectMapper(new NewlineAddingJsonFactory()).writer();
assertThat(writer.writeValueAsString(ImmutableMap.of()), equalTo("{}\n"));
assertThat(writer.writeValueAsString(ImmutableMap.of("foo", "bar")), equalTo("{\"foo\":\"bar\"}\n"));
}
Run Code Online (Sandbox Code Playgroud)
servlet 过滤器也不一定太糟糕,尽管最近 ServletOutputStream 接口更多地涉及到正确拦截。
我发现在较早的 Jackson 版本(例如您的 2.4.4)上通过 PrettyPrinter 执行此操作有问题,部分原因是需要通过 ObjectWriter 对其进行正确配置:仅在 Jackson 2.6 中修复。为了完整起见,这是一个有效的 2.5 解决方案:
@Test
public void append_newline_after_end_of_json() throws Exception {
// Jackson 2.6:
// ObjectMapper mapper = new ObjectMapper()
// .setDefaultPrettyPrinter(new NewlineAddingPrettyPrinter())
// .enable(SerializationFeature.INDENT_OUTPUT);
// ObjectWriter writer = mapper.writer();
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer().with(new NewlineAddingPrettyPrinter());
assertThat(writer.writeValueAsString(ImmutableMap.of()), equalTo("{}\n"));
assertThat(writer.writeValueAsString(ImmutableMap.of("foo", "bar")),
equalTo("{\"foo\":\"bar\"}\n"));
}
public static final class NewlineAddingPrettyPrinter
extends MinimalPrettyPrinter
implements Instantiatable<PrettyPrinter> {
private int depth = 0;
@Override
public void writeStartObject(JsonGenerator jg) throws IOException, JsonGenerationException {
super.writeStartObject(jg);
++depth;
}
@Override
public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException, JsonGenerationException {
super.writeEndObject(jg, nrOfEntries);
if (--depth == 0) {
jg.writeRaw('\n');
}
}
@Override
public PrettyPrinter createInstance() {
return new NewlineAddingPrettyPrinter();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5077 次 |
| 最近记录: |