在生成的JSON末尾添加新行

在生成的JSON末尾添加新行,json,jersey,jackson,Json,Jersey,Jackson,我有一个基于运动衫(1.x)的休息服务。它使用Jackson 2.4.4生成JSON响应。我需要在响应的末尾添加一个换行符(cURL用户抱怨响应中没有新行)。我正在使用打印功能(SerializationFeature.INDENT\u OUTPUT) 当前:{\n“prop”:“value”\n} 通缉:{\n“prop”:“value”\n}\n 我尝试使用自定义序列化程序。我只需要在根对象的末尾添加\n。序列化程序是根据每个数据类型定义的,这意味着,如果此类类嵌套在一个响应中,我将在JSO

我有一个基于运动衫(1.x)的休息服务。它使用Jackson 2.4.4生成JSON响应。我需要在响应的末尾添加一个换行符(cURL用户抱怨响应中没有新行)。我正在使用打印功能(
SerializationFeature.INDENT\u OUTPUT

当前:
{\n“prop”:“value”\n}

通缉:
{\n“prop”:“value”\n}\n

  • 我尝试使用自定义序列化程序。我只需要在根对象的末尾添加
    \n
    。序列化程序是根据每个数据类型定义的,这意味着,如果此类类嵌套在一个响应中,我将在JSON的中间得到<代码> \n>代码>。p>
  • 我想到了子类化
    com.fasterxml.jackson.core.JsonGenerator.java
    ,重写
    close()
    ,在那里我要添加
    writeRaw('\n')
    ,但这感觉非常粗糙

  • 另一个想法是添加Servlet筛选器,它将重新写入Jersey筛选器的响应,添加
    \n
    ,并将ContentLength增加1。看起来不仅粗俗,而且效率低下

  • 我也可以放弃处理序列化内容的工作,而去做
    ObjectMapper.writeValue()+“\n”
    ,但这对我的代码来说是相当麻烦的(需要更改很多地方)

  • 这个问题的干净解决方案是什么

    我发现这些线程用于相同的问题,但没有一个提供解决方案:

    @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();
        }
    }
    

    更新

    最后,我选择了@arachnid的解决方案,使用了
    NewlineAddingPrettyPrinter
    (也是2.6.2版本)。遗憾的是,Jaskson作为Json提供程序时,它不能开箱即用。在
    ObjectMapper
    中更改的
    PrettyPrinter
    不会传播到
    JsonGenerator
    (请参见原因)。为了让它工作,我必须添加
    ResponseFilter
    ,它添加了
    ObjectWriterModifier
    (现在我可以根据输入参数轻松地在pretty print和minimal之间切换):

    @Provider
    公共类PrettyPrintFilter扩展BaseResponseFilter{
    公共ContainerResponse筛选器(ContainerRequest请求、ContainerResponse响应){
    set(新的PrettyPrintToggler(true));
    返回响应;
    }
    最终类PrettyPrintToggler扩展ObjectWriterModifier{
    私有静态最终预打印器NO_PRETTY_PRINT=新最小预打印器();
    私有最终布尔使用预打印;
    公共预打印切换程序(布尔值usePrettyPrint){
    this.usePrettyPrint=usePrettyPrint;
    }
    @凌驾
    public ObjectWriter modify(EndpointConfigBase端点、多值映射响应头、,
    对象值写入、对象编写器w、JsonGenerator g)引发IOException{
    if(使用prettyprint)g.setPrettyPrinter(newnewlineaddingprettyprinter());
    else g.setPrettyPrinter(无漂亮打印);
    返回w;
    }
    }
    }
    
    尚未测试,但以下各项应能正常工作:

    public class MyObjectMapper extends ObjectMapper {
    
           _defaultPrettyPrinter = com.fasterxml.jackson.core.util.MinimalPrettyPrinter("\n");
    
        // AND/OR
    
           @Override
           protected PrettyPrinter _defaultPrettyPrinter() {
                return new com.fasterxml.jackson.core.util.MinimalPrettyPrinter("\n");
           }
    
    }
    
    
    public class JerseyConfiguration extends ResourceConfig {
        ...
        MyObjectMapper mapper = new MyObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT); //enables pretty printing
    
        // create JsonProvider to provide custom ObjectMapper
        JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
        provider.setMapper(mapper);
        register(provider); //register so that jersey use it
    }
    
    不知道这是否是“最干净”的解决方案,但感觉没有其他解决方案那么粗糙

    应该产生类似于

    {\n“根”:“1”\n}\n{\n“根2”:“2”\n}

    但是,如果只有一个根元素,这似乎不起作用

    想法来自

    事实上,包装(而不是子类化)JsonGenerator并不太糟糕:

    servlet过滤器也不一定太糟糕,尽管最近ServletOutputStream接口被更多地用于正确拦截

    我发现通过PrettyPrinter进行此操作在早期的Jackson版本(如2.4.4)上存在问题,部分原因是需要通过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();
        }
    }
    
    @测试
    在_json()的_end_之后,public void append_newline_引发异常{
    //杰克逊2.6:
    //ObjectMapper映射器=新的ObjectMapper()
    //.setDefaultPrettyPrinter(新的NewlineAddingPrettyPrinter())
    //.enable(SerializationFeature.INDENT_输出);
    //ObjectWriter=mapper.writer();
    ObjectMapper mapper=新的ObjectMapper();
    ObjectWriter writer=mapper.writer()。带有(new NewlineAddingPrettyPrinter());
    assertThat(writer.writeValueAsString(ImmutableMap.of()),equalTo(“{}\n”);
    资产(writer.writeValueAsString(ImmutableMap.of(“foo”,“bar”))),
    相等(“{\'foo\':\'bar\'}\n”);
    }
    公共静态最终类NewlineAddingPrettyPrinter
    扩展最小预打印机
    实现可实例化的{
    私有整数深度=0;
    @凌驾
    public void writeStartObject(JsonGenerator jg)抛出IOException,JsonGenerationException{
    超级writeStartObject(jg);
    ++深度;
    }
    @凌驾
    public void writeEndObject(JsonGenerator jg,int nrOfEntries)抛出IOException,JsonGenerationException{
    超级写入对象(jg、nrOfEntries);
    如果(--depth==0){
    jg.writeRaw('\n');
    }
    }
    @凌驾
    公共预打印机createInstance(){
    返回新的NewlineAddingPrettyPrinter();
    }
    }
    
    我已经配置了prettyprint(但没有覆盖默认的
    PrettyPrinter
    ),它给了我类似JSON的信息:
    {\n“prop”:“value”\n}
    。我想我没有清楚地表达我自己-我需要的是在整个JSON实体后面加一行新行,比如:
    {\n“prop”:“value”\n}\n
    。我已经测试了您的解决方案,但它在功能上与我目前的解决方案没有什么不同。我已经为这个问题添加了一些示例。我已经对此进行了反驳,并且关心如何分离根对象。但我会朝这个方向走得更远,看看如果没有第二个根对象,你是否可以用最小预打印器添加一个根分隔符
    @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();
        }
    }