如何在默认情况下使用Sping Boot 和Jackson转义JSON响应中的\n和\t等字符

rhfm7lfc  于 2023-08-08  发布在  其他
关注(0)|答案(1)|浏览(125)

我在Sping Boot 应用程序(版本2.7.13)中返回带有转义字符的JSON时遇到了问题。
下面示例代码中的/demo端点:

package com.example.invalidjson.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @RestController
    @RequestMapping("/")
    public class DemoController {
        @GetMapping(path = "/demo")
        Demo getExample() {
            Demo demo = new Demo();
            demo.setTitle("Example of \n JSON");

            return demo;
        }

        @GetMapping(path = "/read")
        void readExample() {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                Demo demo = objectMapper.readValue("{\"title\" : \"Example of \n JSON\"}", Demo.class);

                System.out.println("Reading succeeded: " + demo.getTitle());
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static class Demo {
        private String title;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }
    }
}

字符串
返回以下JSON:

{"title":"Example of \n JSON"}


问题是这个JSON不能被其他客户端解析。Jackson也没有读过。/read端点引发以下异常:

com.fasterxml.jackson.core.JsonParseException: Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included in string value
 at [Source: (String)"{"title" : "Example of
 JSON"}"; line: 1, column: 25]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391) ~[jackson-core-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:735) ~[jackson-core-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.core.base.ParserBase._throwUnquotedSpace(ParserBase.java:1110) ~[jackson-core-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString2(ReaderBasedJsonParser.java:2155) ~[jackson-core-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString(ReaderBasedJsonParser.java:2126) ~[jackson-core-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getText(ReaderBasedJsonParser.java:320) ~[jackson-core-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:41) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597) ~[jackson-databind-2.13.5.jar:2.13.5]
    at com.example.invalidjson.demo.DemoApplication$DemoController.readExample(DemoApplication.java:34) ~[classes/:na]
...


我的理解是,Jackson作为Sping Boot 的默认JSON解析器,会自动转义像\n\t这样的字符,或者我没有很好地理解文档。
我看到了一些使用JacksonConfiguration的选项,比如:

package com.example.invalidjson.demo;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

@Configuration
public class JacksonConfiguration {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();

        JsonSerializer<String> stringJsonSerializer = new JsonSerializer<String>() {
            @Override
            public void serialize(String value, JsonGenerator generator, SerializerProvider serializers) throws IOException {
                generator.writeString(value.replace("\n", "\\n"));
            }
        };

        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(String.class, stringJsonSerializer);

        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}


就没有别的办法处理吗?
根本的问题是:为什么Jackson会生成一个连自己都无法读取的JSON?

aiazj4mn

aiazj4mn1#

要使用Sping Boot 和Jackson在默认情况下转义JSON响应中的\n和\t等字符,您可以配置Jackson使用的ObjectMapper以启用JsonGenerator.Feature.ESCAPE_NON_ASCII功能。此功能使用Unicode转义序列转义非ASCII字符,其中包括\n和\t等字符。
以下是您的操作方法:
创建配置类以自定义JacksonObjectMapper:
导入com.fasterxml.Jackson.core.JsonGenerator;导入com.fasterxml.Jackson.databind.ObjectMapper; import org.springframework.boot.autocigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
public class MyClass {

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
    return builder -> {
        builder.featuresToEnable(JsonGenerator.Feature.ESCAPE_NON_ASCII);
        // Add any other Jackson customization if needed
    };
}

@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilderCustomizer customizer) {
    ObjectMapper objectMapper = new ObjectMapper();
    customizer.customize(objectMapper);
    return objectMapper;
}

字符串
}
在上面的配置类中,我们为Jackson 2 ObjectMapperBuilderCustomizer定义了一个bean,它启用了JsonGenerator.Feature.ESCAPE_NON_ASCII特性。
我们还为ObjectMapper本身定义了一个bean,在这里我们应用定制器来配置ObjectMapper示例。
有了上面的配置,Sping Boot 将使用定制的ObjectMapper来序列化JSON响应。\n和\t字符(沿着其他非ASCII字符)将使用Unicode转义序列进行转义。
注意:确保您已经在Sping Boot 项目中配置了Jackson依赖项。
就是这样!现在你的JSON响应应该默认包含转义字符,比如\n和\t。

相关问题