Java Spring response JSON String unescaped - java

I have the following Spring Method :
#RequestMapping(value = "/product/{productId}", method = RequestMethod.GET ,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getProductById(
//ProductDTO database query in order to retrieve productg by ID and population
final ObjectMapper objectMapper = new ObjectMapper();
final String json = objectMapper.writeValueAsString(productDTO);
return new ResponseEntity<>(json, HttpStatus.OK);
That returns a product representation in JSON format, the problem that I have is when I return this JSON , in the response I get it escaped like this:
"{\"uid\":\"test\",\"type\":\"Fragrance\",\"modifiedtime\":1575379505000,\"name\":\"test
name\",\"otherProperties\":{\"container\":false,\" ETC...``
I would need it unescaped in the response , how can I achieve this?
The reason I transform the DTO manually is because if I just return the DTO in the ResponseEntity the representation of the JSON handled by Spring is not the same as the one I get using objectMapper.writeValueAsString method , instead of getting this:
"name": "nombre de prueba",
"otherProperties": {
"container": false,
"onlineExclusive": false,
"sizeGuide": "size guide",etc..
I get this:
"name": "nombre de prueba",
"otherProperties": [
{
"key": "container",
"value": {
"type": "boolean",
"value": false
}
},
{
"key": "onlineExclusive",
"value": {
"type": "boolean",
"value": false
}
},
{
"key": "sizeGuide",
"value": {
"type": "string",
"value": "size guide"
}
},
```

Related

Query parameter annotation generated as body param in Swagger?

I have a Restlet API application using the Restlet Swagger extenstion to generate the Swagger json via Swagger2SpecificationRestlet.
// route to generated swagger json
swagger2SpecificationRestlet.attach(router, "/docs");
My routes are defined like this:
router.attach("/path/{pathParam}", MyResource.class);
I have implemented swagger-ui locally and set the initializer url to read the swagger json from /docs. The UI works as expected for all of the routes including the required path parameter inputs however the annotations for the query params are rendering as post body(?) without any of the other defined fields. param inputs:
"parameters": [
{
"name": "pathParam",
"in": "path",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "body",
"required": false,
"schema": {
"type": "string"
}
],
My resource method with annotations:
#ApiOperation(
value="test desc",
httpMethod = "GET",
produces = "application/json",
notes="testing notes"
)
#Get("txt")
public String represent(
#ApiParam(name="queryParam", value = "testing desc")
#QueryParam("queryParam") String queryParam
) throws SQLException { ... }
How can I annotate query params so that swagger generates the correct json configuration?
After looking further into the documentation I came across this:
https://docs.swagger.io/swagger-core/apidocs/com/wordnik/swagger/annotations/ApiImplicitParam.html#paramType()
which states:
public #interface ApiImplicitParam Represents a single parameter in an
API Operation. While ApiParam is bound to a JAX-RS parameter, method
or field, this allows you to manually define a parameter in a
fine-tuned manner. This is the only way to define parameters when
using Servlets or other non-JAX-RS environments.
I replaced ApiParam with ApiImplicitParam which has a field to declare param type and moved the annotation above the method:
#ApiOperation(
value="get stuff",
httpMethod = "GET",
produces = "application/json",
notes="test notes"
)
#Get("txt")
#ApiImplicitParam(
name="queryParam",
dataType = "String",
paramType = "query",
value = "testing query param desc",
defaultValue = "default val")
public String represent() throws SQLException {
return getMethod();
}
Which results in the correctly generated json:
"parameters": [
{
"name": "pathParam",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "queryParam",
"in": "query",
"description": "testing query param desc",
"required": false,
"type": "string",
"default": "default val"
}
]

how to escape part of json loaded as object

I'm not fluent in API testing hence my question. I have a body to POST (mock) that will consist of:
{
"request":
{
"urlPath": "path/to/",
"method": "POST",
"bodyPatterns":[{
"equalToJson" : "{\n\"query\": [\n{\n\"name\": \"name1\",\n\"value\": \"123\"\n },\n{\n\"name\": \"name2\",\n\"value\": \"345\"\n},\n{\n\"name\": \"name3\",\n\"value\": \"someName\"\n}\n],\n\"anotherItem\": [],\n\"side\": 77,\n\"pageSize\": 44\n}", "jsonCompareMode": "LENIENT"
}]
},
"response":
{
"status": 200,
"headers":
{
"Content-Type" : "application/json"
},
"body": "{"items\": [\n{\n\"item\": 1,\n
\"item2\": 2,\n
etc
"\n}\n]\n}"
}
}
I want to use some pojo classes to separately create Request and Response:
public Request initRequest() {
BodyPattern bodyPat = new BodyPattern();
Query query = new Query();
Query query2 = new Query();
Query query3 = new Query();
EqualToJson equalToJ = new EqualToJson();
query.setName("name1");
query.setValue("123");
query2.setName("name2");
query2.setValue("345");
query3.setName("name2");
query3.setValue("someName");
List<Query> queryList = new ArrayList<>();
queryList.add(query);
queryList.add(query2);
queryList.add(query3);
equalToJ.setQuery(queryList);
List<Filter> filtersList = new ArrayList<>();
equalToJ.setFilter(filtersList);
equalToJ.setSide(77);
equalToJ.setPageSize(44);
List<EqualToJson> eqList = new ArrayList<>();
eqList.add(equalToJ);
req.setUrlPath(URL + "/Test001");
req.setMethod("POST");
bodyPat.setEqualToJson(eqList);
bodyPat.setJsonCompareMode("LENIENT");
List<BodyPattern> bodyPatList = new ArrayList<>();
bodyPatList.add(bodyPat);
req.setBodyPatterns(bodyPatList);
return req;
}
To see it in more user-friendly view, here you go:
{
"request": {
"urlPath": "/path/to",
"method": "POST",
"bodyPatterns": [
{
"equalToJson": {
"query": [
{
"name": "name1",
"value": "123"
},
{
"name": "name2",
"value": "345"
},
{
"name": "name3",
"value": "someName"
}
],
"filter": [
],
"side": 77,
"pageSize": 44
},
"jsonCompareMode": "LENIENT"
}
]
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"side": 77,
"pageSize": 44,
"items": [
{
"name1": "123",
"name2": "345",
"name3": "someName"
etc...
}
]
}
}
}
Similarly, I do with Response.
My question is, how can I make to have just a part of this json (BodyPatters) as escaped signs? Mock is created this way that it only accepts escaped characters in this part of json.
I can of course hardcode this payload, but I want to have control over those fields' values and steer them, as parameters.
I really have no idea how to handle this.
You can use objectmapper of jackson to convert Object to String. For example:
void name2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Query query = new Query("name1", "123");
EqualToJson equalToJson = new EqualToJson();
equalToJson.setQuery(Arrays.asList(query));
BodyPattern bodyPattern = new BodyPattern();
bodyPattern.setEqualToJson(mapper.writeValueAsString(equalToJson));
String bodyPatternText = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(bodyPattern);
System.out.println(bodyPatternText);
}
#Data
#AllArgsConstructor
static class Query{
private String name;
private String value;
}
#Data
static class EqualToJson {
private List<Query> query;
}
#Data
static class BodyPattern {
private String equalToJson;
}
This is a result:
{
"equalToJson" : "{\"query\":[{\"name\":\"name1\",\"value\":\"123\"}]}"
}

How can I split and print a section of JSON/String?

I have a JSON Schema fetched from a DB, Which is now stored in a string in Java. I want to print only a section of schema but not all. How can I split the JSON/String and print.
I have tried converting the String back to JSON format. But not sure how to separate the required content. Also split method didn't worked for me as well.
Input:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"employee_id": {
"type": "string"
},
"course_id": {
"type": "string"
},
"college_id": {
"type": "string"
}
},
"required": [
"employee_id",
"course_id",
"college_id"
]
}
Expected Result:
employee_id, course_id, college_id
As your question doesn't provide any details on which library you are using to parse the JSON document, I have put together some approaches using popular JSON parsing libraries for Java.
JsonPath
It is pretty straightforward to be achieved with JsonPath:
List<String> required = JsonPath.parse(json).read("$.required");
Jackson
It also could be achieved with Jackson:
ObjectMapper mapper = new ObjectMapper();
List<String> required = mapper.convertValue(mapper.readTree(json).get("required"),
new TypeReference<List<String>>() {});
Gson
In case you prefer Gson:
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
List<String> required = gson.fromJson(jsonObject.getAsJsonArray("required"),
new TypeToken<List<String>>() {}.getType());
JsonPath with Jackson or Gson
Depending on your needs, you could combine JsonPath with Jackson or Gson:
Configuration conf = Configuration.builder()
.jsonProvider(new JacksonJsonProvider())
.mappingProvider(new JacksonMappingProvider())
.build();
Configuration conf = Configuration.builder()
.jsonProvider(new GsonJsonProvider())
.mappingProvider(new GsonMappingProvider())
.build();
List<String> required = JsonPath
.using(conf)
.parse(json)
.read("$.required", new TypeRef<List<String>>() {});
String str=
"{
"key":{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"employee_id": {
"type": "string"
},
"course_id": {
"type": "string"
},
"college_id": {
"type": "string"
}
},
"required": [
"employee_id",
"course_id",
"college_id"
]
}
}
";
JSONObject jsonObj=new JSONObject(str);
JSONObject keyJon= jsonObj.getJSONObject("key");
String strUrl=keyJon.getString("$schema");
System.err.println("str "+strUrl);
I've made a helper library that uses gson and has ability to search json for subtrees/elements:
https://github.com/Enerccio/gson-utilities
In your case you would do
List<JsonElement> contents = JsonHelper.getAll(data, "key.required", x -> x instanceof JsonPrimitive);
System.out.print(contents.stream().map(JsonElement::getAsString).collect(Collectors.joining(", ")));
But you have invalid JSON, the valid version would be:
{
"key":{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"employee_id": {
"type": "string"
},
"course_id": {
"type": "string"
},
"college_id": {
"type": "string"
}
},
"required": [
"employee_id",
"course_id",
"college_id"
]
}
}
The below-mentioned method solved my problem.
JSONObject jsonObject = new JSONObject(key);
JSONArray req = jsonObject.getJSONArray("required");
System.out.println("Required Parameters : "+req);

Spring Data Rest + Spring Data Mongo - can't update numer of elements on list in object

so I have got a problem with updating object which contain a list of elements. My object definition:
public class Project {
private String _id;
private String name;
private List<Pair> config;
}
And the Pair object:
public class Pair {
private String key;
private String value;
}
I'm using Spring Rest repository to provide the Rest Api and everything is stored in mongodb. Just using the simple interface to create mongoRepository
#RepositoryRestResource(collectionResourceRel = "project", path = "projects")
public interface ProjectRepository extends MongoRepository<Project, String>{
Project findByName(String name);
}
When I create a project object with json (sending POST to /projects):
{
"name": "test_project",
"config": [{
"key": "port",
"value": "12"
},{
"key": "port2",
"value": "123"
}]
}
I have got the proper response and object has been created:
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[
{
"key": "port",
"value": "12"
},
{
"key": "port2",
"value": "123"
}]
}
So right now I would like to send PUT to update my object and I'm getting strange results:
For example sending following body with PUT to
localhost:8151/projects/58c916fad76a3a186731ad28
{
"name": "test_project",
"config": [{
"key": "port",
"value": "12"
}]
}
So I want to remove one element from list. The response is (Status OK):
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[
{
"key": "port",
"value": "12"
},
{
"key": "port2",
"value": "123"
}]
}
So the number of elements didn't change what I expected (my expectations was that the new list replace the old one). Next test:
I would like to add one new element to list:
{
"name": "test_project",
"config": [{
"key": "port",
"value": "12"
},{
"key": "port1",
"value": "13"
},{
"key": "port2",
"value": "14"
}]
}
Gives following result:
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[
{
"key": "port",
"value": "12"
},
{
"key": "port1",
"value": "13"
}]
}
New element hasn't been added but the second element has changed.
It looks like instead of List mongo save it as an array and can't change the size but can update the element. Am I right?
But, if it would be true the next test should return the same result:
I'm sending the empty list of config and I'm expect that I will have an two-element list.
{
"name": "test_project",
"config": []
}
But what is strange for me I have got the following result:
{
"_id": "58c916fad76a3a186731ad28",
"name": "test_project",
"createdAt": "2017-03-15T10:27:06.295+0000",
"modifiedAt": "2017-03-15T10:27:06.295+0000",
"config":[]
}
So the number of elements has been updated.
To be honest right now I'm totally confused how it works. Could anyone explain how Spring rest repository handle this action and propose a proper solution for this problem?
I am having the same issue. As a workaround you can send a PATCH request. This updates the array properly.

Spring Rest Web service returning 415

I have Spring web service from the following. JSON for swagger
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Extended User Management API",
"description": "This is communicate with an extended user management webservice to test the swagger API for learning"
},
"schemes": [
"http"
],
"basePath": "/UserManagement/rest/UserService",
"host": "127.0.0.1:8089",
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"paths": {
"/users": {
"get": {
"responses": {
"200": {
"description": "An array of users",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/addUser": {
"post": {
"summary": "Add an additional user",
"description": "This service is used to add and additional user to the list of users.",
"parameters": [
{
"name": "user_id",
"in": "query",
"description": "Unique id of the user to be added.",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "name",
"in": "query",
"description": "Name of the user to be added.",
"required": true,
"type": "string"
},
{
"name": "profession",
"in": "query",
"description": "Profession of the user to be added.",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"User": {
"type": "object",
"properties": {
"user_id": {
"type": "integer",
"format": "int32",
"description": "This is unique id that is assigned to each user."
},
"name": {
"type": "string",
"description": "This is the name of the user"
},
"profession": {
"type": "string",
"description": "This is the profession that the user holds"
}
}
},
"Error": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"fields": {
"type": "string"
}
}
}
}
}
I generated the code and resolved all the error in the project. The I got the application to run in Spring boot main with out any problems. The issue that I'm facing now is that on accessing the get web service "/users", I'm getting an error from the service.
I tried debugging the spring application I came to find that the intended service is not even hit. The code for service is given below.
#javax.annotation.Generated(value = "class io.swagger.codegen.languages.SpringCodegen", date = "2016-10-24T09:36:32.738Z")
#Api(value = "users", description = "the users API")
public interface UsersApi {
#ApiOperation(value = "", notes = "", response = User.class, responseContainer = "List", tags={ })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "An array of users", response = User.class),
#ApiResponse(code = 200, message = "Unexpected error", response = User.class) })
#RequestMapping(value = "/users",
produces = { "application/json" },
consumes = { "application/json" },
method = RequestMethod.GET)
ResponseEntity<List<User>> usersGet();
}
Implementation of this interface is given below
#javax.annotation.Generated(value = "class io.swagger.codegen.languages.SpringCodegen", date = "2016-10-24T09:36:32.738Z")
#Controller
public class UsersApiController implements UsersApi {
UserDao udao = new UserDao();
public ResponseEntity<List<User>> usersGet() {
return new ResponseEntity<List<User>>(udao.getAllUsers(), HttpStatus.OK);
}
}
Can please some one tell me what is the mistake that I made so that I can solve this.
Well you are using an unsupported media type as the exception says.
Have a look at your #RequestMapping annotation:
#RequestMapping(value = "/users",
produces = { "application/json" },
consumes = { "application/json" },
method = RequestMethod.GET)
ResponseEntity<List<User>> usersGet();
Either you remove the consumes key or you support the Content-Type in your GET request.
Edit: maybe it would be a better option to remove the consumes key. I don't think it is a good idea to consume any json in a GET request.

Categories