Returning JSON as Response Spring Boot
Solution 1
You need to define your json attribute as JsonNode so jackson can read it back and forrward, but mark is as @Transient
so JPA does not try to store it on database.
Then you can code getter/setter for JPA, where you translate from JsonNode to String back and forward. You define a getter getJsonString
that translate JsonNode json
to String
. That one can be mapped to a table column, like 'json_string', then you define a setter where you receive the String
from JPA and parse it to JsonNode that will be avaialable for jackson, jackson then will translate it to a json object not a string as you mention.
@Entity
@Table(name = "model")
public class SomeModel {
private Long id;
private String col1;
// Attribute for Jackson
@Transient
private JsonNode json;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@Column(name ="col1")
public String getCol1() {
return col1;
}
// Getter and setter for name
@Transient
public JsonNode getJson() {
return json;
}
public void setJson(JsonNode json) {
this.json = json;
}
// Getter and Setter for JPA use
@Column(name ="jsonString")
public String getJsonString() {
return this.json.toString();
}
public void setJsonString(String jsonString) {
// parse from String to JsonNode object
ObjectMapper mapper = new ObjectMapper();
try {
this.json = mapper.readTree(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Notice, @Column
are defined at gettters because we need to indicate JPA to use getJsonString
and JPA requires consistency so all column's getters must be mark with @Columns
.
Solution 2
Change your some model class like this
@Entity
@Table(name="some_table")
public class SomeModel {
@Id
@Column(name="p_col", nullable=false)
private Integer id;
@Column(name="s_col")
private String name
@Column(name="t_col")
private String json; // this column contains json data
@Column(name = "t_col", columnDefinition = "json")
@Convert(attributeName = "data", converter = JsonConverter.class)
private Map<String, Object> json = new HashMap<>();
//constructors
//getters and setters
}
Write a json converter class.
@Converter
public class JsonConverter
implements AttributeConverter<String, Map<String, Object>>
{
@Override
public Map<String, Object> convertToDatabaseColumn(String attribute)
{
if (attribute == null) {
return new HashMap<>();
}
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
}
catch (IOException e) {
}
return new HashMap<>();
}
@Override
public String convertToEntityAttribute(Map<String, Object> dbData)
{
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
}
catch (JsonProcessingException e)
{
return null;
}
}
}
It will convert database json attribute to your desire results. Thanks
Solution 3
In your controller add json response:
@RequestMapping(value = "/getsome", method = RequestMethod.GET, produces = "application/json"
And wrap the getData string as response
public class StringResponse {
private String response;
public StringResponse(String s) {
this.response = s;
}
}
404or505
Updated on June 14, 2022Comments
-
404or505 almost 2 years
I am trying to get rest response as json instead I am getting as string.
Controller
@RestController @RequestMapping("/api/") public class someController{ @Autowired private SomeService someService; @GetMapping("/getsome") public Iterable<SomeModel> getData(){ return someService.getData(); } }
Service
@Autowired private SomeRepo someRepo; public Iterable<someModel> getData(){ return someRepo.findAll(); }
Repository
public interface SomeRepo extends CrudRepository<SomeModel,Integer>{ }
Models
@Entity @Table(name="some_table") public class SomeModel{ @Id @Column(name="p_col", nullable=false) private Integer id; @Column(name="s_col") private String name @Column(name="t_col") private String json; // this column contains json data //constructors, getters and setters }
when I run localhost:8080/api/getsome I am getting:
[ { "p_col":1, "s_col":"someName", "t_col":" {\r\n\t"school_name\":\"someSchool\",\t\r\n\t"grade\":"A\",\r\n\t\"class\": [{\"course\":"abc",\t"course_name\":\"def" }]}" } ]
Field t_col is returning string instead of json. How do I get json objects in response?
As for the database, the three columns are int, varchar and varchar.
Any help would be appreciated. Thanks !!
-
404or505 about 5 yearsThank you, it worked for me !! How does it work the other way around, if I need to save json input as string in db?
-
Cristian Colorado about 5 yearsThat part is incorporated in the solution, you see when JPA is trying to translate the POJO to an insert statement, it will execute the
getJsonString
method, as it is marked with@Column
liked tojsonString
column. So as long as you have json/jsonString getters/setters like this it will work like you expected. -
404or505 about 5 yearsI tried various ways using JsonNode to save raw Json objects to string but couldn;t get it to work. I am getting following error "status": 400, "error": "Bad Request", "message": "JSON parse error: Cannot deserialize instance of
java.util.ArrayList
out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance ofjava.util.ArrayList
out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 1, column: 1]", "trace": "org.springframework.http.converter.HttpMessageNotReadableException: JSON parse e -
Cristian Colorado about 5 yearsYou need to be more specific on the implementation you are trying to make, in the example you provide there is no element with array.
-
404or505 about 5 yearsFor the POST mapping I am providing the following controller: @PostMapping("/saverawjson") public void saveRawJson(@RequestBody SomeModel someModel){ //..... someRepository.save(someModel) } I am using following for repo public interface SomeRepo extends CrudRepository<SomeModel,Integer>{}
-
404or505 about 5 yearsUpdate: there are no errors, it was my mistake to provide wrong json but the column (string) with json is populating as null.
-
zar3bski about 3 yearsInteresting quick fix but I endup with error 406 while calling my APIs. What is it waiting for exactly?