Why are related entities being escaped when converted to JSON?



I have a Spring MVC controller which fetches some entities via a query. These entities have a related entity that is eagerly fetched. However, when I use JSONObject.toString() it escapes the related model data:

    {
        "totalRecords": 29,
        "hasErrors": false,
        "data": {
            "regs": [
                {
                    "is_active": 1,
                    "name": "NAR",
                    "modified": "09/14/2020 08:46 AM",
                    "language": "{"name":"English","id":1,"shortcode":"en"}", <--
                    "id": 1,
                },
                {
                    "is_active": 1,
                    "name": "SAR",
                    "modified": "09/14/2020 08:46 AM",
                    "language": "{"name":"English","id":1,"shortcode":"en"}", <--
                    "id": 2,
                }
            ]
        }
    }

The value in the language property is an escaped JSON object from the related entity. Why is it being escaped like that? How do I prevent it?

// Entity Reg

public class CmsRegions extends CmsModel implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    
    @JsonManagedReference
    @ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.DETACH)
    @JoinColumn(name = "language_id", referencedColumnName = "id")
    private SysLanguages language;
}

// Entity Language

public class SysLanguages extends Model implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "name")
    private String name;

    
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "language")
    private Set<CmsRegions> regions;
    
}

// Controller

...
   JSONArray objs  = new JSONArray();
   for (CmsRegions region : regions) {
                JSONObject jsonRegion = new JSONObject();
                
                jsonRegion.put("id", region.getId());
                jsonRegion.put("name", region.getName());
                jsonRegion.put("description", region.getDescription());
                jsonRegion.put("language", region.getLanguage());
                objs.put(jsonRegion);
   }

   String response = new JSONObject(payload).toString();

...

Payload is just a POJO that is the data object we use to transmit data back from the API.

Why is language getting escaped? Is there an annotation I am missing?

UPDATE

I know that this is not JSONObject doing it, as I created a test case here:

https://repl.it/repls/GlossyScaredLock

It seems as though the occurrence happens when the related model is serialized, then attached to the model, which is then serialized. Not sure how to prevent it .

Answer

This happens due to the serialization, there are some chars which are replaced in order for the message to be parsed properly :

Backspace is replaced with b, Form feed is replaced with f, Newline is replaced with n, Carriage return is replaced with r, Tab is replaced with t, Double quote is replaced with “, Backslash is replaced with

You can use StringEscapeUtils.unescapeJava(stringToUnEscape) from Apache Commons lang in order to remove those escaping after parsed.



Source: stackoverflow