杰克逊在json中添加了反斜杠

时间:2017-01-23 21:19:17

标签: java json rest jersey jackson

我正在Jersey上构建REST服务,并使用Jackson从我的模型的java类中生成JSON。模型具有绝对简单的值,我认为这是最典型的情况。但我得到了奇怪的结果:

[{\"name\":\"Nick\",\"role\":\"admin\",\"age\":\"32\",\"rating\":47}]

我期待的结果:

[{"name":"Nick","role":"admin","age":"32","rating":47}]

我的字段源值不包含任何特殊字符。这些都很简单。

有我的Java课程。 实体:

public class User {

  private String name;

  private String role;

  private String age;

  private Integer rating;

休息服务等级:

@ServiceConfig(contextName = "myContext")
@Path("/myrest")
public class MyRestService {

  private static final String JSON_CONTENT_TYPE = MediaType.APPLICATION_JSON + ";charset=UTF-8";

  @Context
  protected HttpServletResponse response;

  @GET
  @Path("/users")
  @OpenTransaction
  @Produces({MediaType.APPLICATION_JSON})
  public String findUsers(@QueryParam("department") String department) {

    response.setContentType(JSON_CONTENT_TYPE);
    PDTResponse.status(response).sendStatus(Response.Status.OK.getStatusCode());

    List<User> users = new ArrayList<>();
    users.add(new User("Nick", "admin", "32", 47));

    String jsonInString;
    ObjectMapper mapper = new ObjectMapper();
    try {
        jsonInString = mapper.writeValueAsString(users);
    } catch (JsonProcessingException ex) {
        jsonInString = "thrown exception: " + ex.getMessage();
    }
    return jsonInString;
}

我尝试对字符串属性使用注释@JsonRawValue

@JsonRawValue
private String name;

但是这个案子的结果是:

[{\"name\":Nick,\"role\":admin,\"age\":32,\"rating\":47}]

我希望:

[{"name":"Nick","role":"admin","age":"32","rating":47}]
很明显,杰克逊以某种方式逃脱了结果json的回应。但为什么要这样做,最重要的是如何避免呢?他们自己只是字符串!没有任何引号或特殊字符。

我使用Java 7Jackson 2.6.1。并Postman来测试结果。 有什么想法来解决我的问题吗?

10 个答案:

答案 0 :(得分:3)

java中的所有字符串都必须转义它们中的引号。所以jsonInString应该有斜杠。当你输出jsonInString虽然它不应该有引号。你是在调试器中看它吗?

答案 1 :(得分:1)

您可以配置ObjectMapper:

final ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
String jsonUsers = mapper.writeValueAsString(users);

更多信息here

答案 2 :(得分:1)

看起来你的JAX-RS资源类太复杂了。

要将Jackson用作Jersey 2.x的JSON提供程序,您不需要像这样创建ObjectMapper实例。有更好的方法来实现它。继续阅读以了解更多详情。

添加Jackson模块依赖项

要将Jackson 2.x用作JSON提供程序,您需要将jersey-media-json-jackson模块添加到pom.xml文件中:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.25.1</version>
</dependency>

注册Jackson模块

然后在JacksonFeature / Application子类中注册ResourceConfig

@ApplicationPath("/api")
public class MyApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(JacksonFeature.class);
        return classes;
    }
}
@ApplicationPath("/api")
public class MyApplication extends ResourceConfig {

    public MyApplication() {
        register(JacksonFeature.class);
    }
}

如果您没有Application / ResourceConfig子类,则可以在web.xml部署描述符中注册JacksonFeature。可以在jersey.config.server.provider.classnames初始化参数的逗号分隔值中提供特定资源,提供程序和功能完全限定的类名。

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.jackson.JacksonFeature</param-value>
</init-param>

杰克逊提供的MessageBodyWriterJacksonJsonProvider。有关如何将Jackson用作JSON提供程序的更多详细信息,请查看此answer。如果您需要自定义ObjectMapper,请参阅此answer

修复资源类

通过使用上述方法,资源类可以简单如下:

@Path("/users")
public class MyRestService {

  @GET
  @Produces({MediaType.APPLICATION_JSON + ";charset=UTF-8"})
  public List<User> findUsers() {

    List<User> users = new ArrayList<>();
    users.add(new User("Nick", "admin", "32", 47));

    return Response.ok(users).build();
}

请求此类端点时,它会为您提供预期的JSON结果。

答案 3 :(得分:1)

执行此操作。

ObjectMapper mapper = new ObjectMapper();
mapper.getFactory().setCharacterEscapes(new JsonUtil().new CustomCharacterEscapes());
ObjectWriter writer = mapper.writer();

String jsonDataObject = mapper.writeValueAsString(configMap);       

public class CustomCharacterEscapes extends CharacterEscapes {

private final int[] _asciiEscapes;

    public CustomCharacterEscapes() {
       _asciiEscapes = standardAsciiEscapesForJSON();
       //By default the ascii Escape table in jackson has " added as escape string
       //overwriting that here.
       _asciiEscapes['"'] = CharacterEscapes.ESCAPE_NONE;
     }

     @Override
     public int[] getEscapeCodesForAscii() {
       return _asciiEscapes;
     }

     @Override
     public SerializableString getEscapeSequence(int i) {
       return null;
    }
  }

答案 4 :(得分:0)

我也有同样的问题并尝试了不同的解决方案,但不起作用。问题不在于映射器,而在于映射器的输入。在你的情况下:
    jsonInString = mapper.writeValueAsString(users);
''users'是一个集合。您需要将每个用户转换为JSONObject,将其添加到JSONArray,然后使用阵列上的映射器:像这样     JSONArray users = new JSONArray(); for (Collection user : usersCollection) { JSONObject user = new JSONObject(mapper.writeValueAsString(user)); users.put(user); } mapper.writeValueAsString(user));

答案 5 :(得分:0)

这应该不是问题,只需要在javascript中解析并使用它:JSON.parse(response)

答案 6 :(得分:0)

如果您使用Spring和@ControllerAdvice for JSONP,那么为JSON字符串创建一个包装器并在属性上使用@JsonRawValue。 JSONP @ControllerAdvice不会包装String响应,它需要一个Object。

public class JsonStringResponse {    
    @JsonValue
    @JsonRawValue
    private String value;

    public JsonStringResponse(String value) {
        this.value = value;
    }
}  

@GetMapping
public ResponseEntity<JsonStringResponse> getJson() {
    String json = "{"id":2}";
    return ResponseEntity.ok().body(new JsonStringResponse(json));
}


@ControllerAdvice
public class JsonpControllerAdvice extends AbstractJsonpResponseBodyAdvice {
    public JsonpControllerAdvice() {
        super("callback");
    }
}

响应是一个json对象{"id":2}
如果存在回调参数,则响应为callbackparameter({"id":2});

答案 7 :(得分:0)

我不知道为什么,但是就我而言,这样做是可行的:

private static final String COOKIE_TEMPLATE = "{0}={1};Version={2};Domain={3};Max-Age={4};Path='/'";

response.addHeader("Set-Cookie", MessageFormat.format(COOKIE_TEMPLATE, cookie.getName(),cookie.getValue(), cookie.getVersion(), cookie.getDomain(),Integer.toString(cookie.getMaxAge())));
return ResponseEntity.ok(...);

cookie是一个javax.servlet.http.Cookie,而cookie.getValue()包含一个由

产生的字符串
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);

如果我使用

response.addCookie(cookie)

我得到的Cookie定义为带有反斜杠的JSON。

但是,如果我使用

response.addHeader("Set-Cookie",MessageFormat(TEMPLATE,cookie.get...))

我管理了与JSON相同的Cookie定义,但没有反斜杠。

如果有多个Cookie,则addHeader(“ Set-Cookie”)仅创建/更新所需的Cookie。其他的将得到维护,不会被更改。

答案 8 :(得分:0)

public class StateDate{
    @JsonRawValue
    Boolean state;
    @JsonRawValue
    String date;

    public String toJson() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(JsonWriteFeature.QUOTE_FIELD_NAMES.mappedFeature(), false);
        try {
            return mapper.writeValueAsString(this);
        } catch (com.fasterxml.jackson.core.JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}

答案 9 :(得分:0)

我遇到了类似的问题,以下配置将有助于解决问题:

final ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, false);