【问题标题】:How to avoid escape characters in Spring REST Controller response that returns list of JSON strings?How to avoid escape characters in Spring REST Controller response that returns list of JSON strings?
【发布时间】:2022-12-27 15:59:07
【问题描述】:

Use case: Return a list of JSON Strings from Spring Rest Controller (the JSON strings come from a third party library).

Problem: Response from REST Controller has escape characters. This happens only when the return type is List or array or any other collection type. Returning a single string works fine.
How to return list of JSON formatted strings but avoid the escape characters.

Code:

import java.util.Arrays;
import java.util.List;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("restjson")
public class RestJsonController {

    @GetMapping(value="list", produces = {MediaType.APPLICATION_JSON_VALUE})
    public List<String> getValues(){
        String value1 = "{\"name\":\"John\", \"age\":30}";
        String value2 = "{\"name\":\"Tom\", \"age\":21}";
        
        return Arrays.asList(value1, value2);
        //response has escape characters: 
        //["{\"name\":\"John\", \"age\":30}","{\"name\":\"Tom\", \"age\":21}"]
    }

    @GetMapping(value="single", produces = {MediaType.APPLICATION_JSON_VALUE})
    public String getValue(){
        String value1 = "{\"name\":\"John\", \"age\":30}";
        String value2 = "{\"name\":\"Tom\", \"age\":21}";
        
        return value1.concat(value2);
        //response has no escape characters: 
        //{"name":"John", "age":30}{"name":"Tom", "age":21}
    }
}

Springboot version: 2.7.0
Full code at: https://github.com/rai-sandeep/restjson/blob/main/src/main/java/com/sdprai/restjson/controller/RestJsonController.java

EDIT:
To avoid any confusion related to string concatenation, I have updated the code (see below). Returning a list even with just one JSON string results in escape characters in the response. But returning just a string does not have this problem. I don't understand the reason behind this difference. For my use case, is there a way to return a list of JSON strings without the escape characters?

import java.util.Collections;
import java.util.List;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("restjson")
public class RestJsonController {

    @GetMapping(value="list", produces = {MediaType.APPLICATION_JSON_VALUE})
    public List<String> getValues(){
        String value1 = "{\"name\":\"John\", \"age\":30}";
        
        return Collections.singletonList(value1);
        //returns: ["{\"name\":\"John\", \"age\":30}"]
    }

    @GetMapping(value="single", produces = {MediaType.APPLICATION_JSON_VALUE})
    public String getValue(){
        String value1 = "{\"name\":\"John\", \"age\":30}";
        
        return value1;
        //returns: {"name":"John", "age":30}
    }
}

【问题讨论】:

  • return value1.concat(value2); - does not produce json.
  • Agreed, but that was just a hack I tried to get around the problem. To make it a valid json, I have to format it as a json array. And see edit, I used a single string to avoid confusions related to concatenation.
  • I'm having the same issue where I need to return the List&lt;String&gt; in ResponseEntity where this String contains a single JSON String. And while sending the response via ResponseEntity serializes the whole List object as well try to serialize the single value of List which is json. Do you found any solution for this?
  • @Pash0002 No, I haven't found a good solution. As a workaround, I'm returning a single json string from the list, but it's not ideal. return StringUtils.join("[", list.stream().collect(Collectors.joining(",")), "]");
  • @Sandeep Rai You can serialize using the ObjectMapper (Jackson library). But for that you need to change return type to String. This worked for me..

标签: java spring spring-boot spring-restcontroller


【解决方案1】:

Basically, Spring MVC (a part of spring boot responsible for handling the Rest Controllers among other things) handles the JSON responses by converting the regular java objects to a valid json string (without backslashes).

So the question is why do you need to work with Strings at all? Try the following code:

public class Person {
   private String name;
   private int age;
   // constructors, getters, etc.
}

 @GetMapping(value="list", produces = {MediaType.APPLICATION_JSON_VALUE})
    public List<Peron> getValues(){
        Person value1 = new Person("John", 30);
        Person value2 = new Person("Tom", 21);
        
        return Arrays.asList(value1, value2);

    }

Now if you say that the strings like {"name":"John", "age":30} are already coming to you from some thirdparty and you're kind of "forced" to return a List&lt;String&gt; instead of List&lt;Person&gt; this is like saying - I don't want spring to convert anything for me, I'll do it by myself. In this case you should understand why does your thirdparty returns string like this and what you can do with it

【讨论】:

  • Yes, I'm kind of forced to use the string returned by third party. Converting to objects would be an option, but I'm trying to avoid it since my real use case has a lot of fields and my intention is only to return the json. What bugs me is that returning a single string looks fine and only lists have the problem (see edit where I used a single string to avoid confusion).
【解决方案2】:

You can try this to avoid escaping.

@GetMapping(value="list", produces = {MediaType.APPLICATION_JSON_VALUE})
    public String getValues(){
        String value1 = "{"name":"John", "age":30}";
        String value2 = "{"name":"Tom", "age":21}";
        return Arrays.asList(value1, value2).toString();
    }

Upvote & Accept if this works.

【讨论】:

  • This works! I would have preferred to return a list, but this seems to be the neatest work around. Thanks @Pash0002!
【解决方案3】:
value1.concat(value2);

Above code joining two Strings so no escaping characters are produced in result String.

        String value1 = "{"name":"John", "age":30}";
        String value2 = "{"name":"Tom", "age":21}";
        
        return Arrays.asList(value1, value2);

In the above code, you are adding a String to the list. So you see escape characters i.e " for ".

If you want an Object list, convert String to Object using object mapper or GSON library and add these objects to the list.

UPDATE

You are adding JSON(which is String) to the list. So you got a string with an escape character.

There is another way you can do this. create a JSON object and add response1, and response2 to that object and return that object.

【讨论】:

  • See edit where I used a single string to avoid confusion. Converting to objects would be an option, but I'm trying to avoid it since my real use case has a lot of fields and my intention is only to return the json.
  • Got your point, you are creating an array with different JSON. But JSON is the string in this case. So you got a string with " characters. you can create a JSON object attached to a different JSON and return it as a string.
【解决方案4】:

I know it's a little late, But I hope it will be helpful to others I was having an almost similar issue

There's a field in my response DTO object called String additionalLanguages Basically, it's a JSON object represented as String. Normally when I return the response I get something like this, a string with escape characters Eg: "additionalLanguages": "[{"abbr":"ar","title":"الأماكن"}]", Inorder to fix this I Just had to add an annotation

@JsonRawValue

Now the response Looks like this

 "additionalLanguages": [
        {
            "abbr": "ar",
            "title": "الأماكن"
        }
    ],

【讨论】:

    猜你喜欢
    • 2022-12-27
    • 2022-12-02
    • 2022-12-02
    • 2022-12-27
    • 2022-12-28
    • 2022-12-28
    • 1970-01-01
    • 2022-12-27
    • 2022-12-26
    相关资源
    最近更新 更多