How to annotate a request body that is oneOf external models? - java

I'm working on documenting an API made with RESTeasy + Jackson in Java using Swagger/OpenAPI (version 1.5.18 - I did add in v3 OAS 2.0.1 to try oneOf/anyOf). One of the endpoints takes in a String as a request body, which is then transformed into one of several classes. The documentation needs to display each of these models so that users can see them. The models are defined in another project. Is there a way to do this through annotations? The closest thing I've found is adding #RequestBody(content=#Content(schema=#Schema(oneOf= {class1.class, class2.class}))) but haven't been able to get it to add the model using that. I also tried adding a dummy class with #ApiModel(subTypes={class1.class, class2.class}. I don't want to add additional endpoints for each object type due to code maintainability.
My question is: is it possible to add the models through annotations while leaving the input type as String?
Here is the relevant code:
#POST
#Path("/{filetype}/new")
#Consumes("application/json")
public Response writeFile(
#ApiParam(required=true, allowableValues = "class1, class2") #PathParam("filetype") String filetype,
#RequestBody(content=#Content(schema=#Schema(oneOf= {class1.class, class2.class}))) String inputFile
) {
return validateFileAndSaveToServer(filetype, inputFile);
}

Related

Can we create an object in Java with out class like in js or python with random key and values

Like in other programing languages - python or JS, when we create a rest api specifically post for the request body we attract some JSON Object
EX:
url: .../employee (Post)
request body: {option: {filter: "suman"}}
In Python or JS we can just do request_body.option.filter and get the data
How can I achieve the same with Java ?
Do I need need to create a class for the reqeust_body and for option and make an instance object request_body
This depends with other framework elements you use in your application. For example if you bring Spring into the scene, you would be looking to use in built features like dependency injection and support for hibernate (JPA implementation), which depends on the concept of entities that are POJOs with extra annotations. So yes you would need to define entity classes and DTOs for those.
I was able to parse the request body with JSONObject like below
#PostMapping("/customers")
public List<Customer> getCustomerById(#RequestBody Map<String, Object> req) {
// {option: {filter: "alf"}}
JSONObject json = new JSONObject(req);
System.out.println(json.toString(4));
System.out.println(json.getJSONObject("option").get("filter"));
-----------------------
-----------------------
-----------------------
}
Output

RestTemplate Project: the DTO fields changing on their own

So I made Rest Client using Spring Boot that is consuming a Rest Web Service. I am passing the required requestbody but on printing the requestbody out it is not the same as my input.
For Example: What I entered was TransactionId then it would be changed to transactionId, AB_NAME would be changed to ab_NAME.
So all these fields get assigned null values.
The ResponseEntity being formed also does the same thing. I don't know why this is happening.
The dtos I have made are in line with the input I want to send so I don't know how they are changing on their own.
EDIT: So basically the web service dto fields are not using the Java naming convention but JSON automatically assumes them to be, had to use #JsonProperty to make sure the fields remain the same. Thanks for all of your help.
See your request body properties names and your model properties name should be the same as case. Writing here one example
DTO
publi class SomeName{
private string transactionId;
private string ab_NAME;
}
Sending body format should be
{
"transactionId":"11111",
"ab_NAME":"ABCDE"
}
Thanks.

Swagger annotations for restful services with JSON data type and without Java Models usage

I have written swagger annotations for my rest servcie like this.
#Post
#Path("/updateDocument")
#ApiOperation(value = "updateDocument", notes = "This will do a checkout and
checkin services", response = Response.class, responseContainer = "application/json")
#Produces("application/json")
#Consumes("application/json")
public String updateDocument(String data) {
return data;
}
Using this, Model Schema is displayed empty on Swagger UI for this operation. Unless I create Java model class, Model Schema is not displayed.
Can some one give some idea, How to get the Schema definition for JSON data types? My Restful Service accepts JSON and process JSON without using any Java Models.
Using Java Models, needs unnecessary conversions of the data.
Is there any flexibility for the JSON definition file can be created and linked instead of the Java Model?
Any help is highly appreciated.
As per your method declaration, It takes a String as a argument. This is all that swagger can read. How will it know that this String can be a json and it can be of xyz structure. So it cannot display you model schema, Unless you specify a Java Model

How can I use my own annotation for Swagger?

How can I use my own annotation for building swagger ui page.
For example I defined annotation and use it:
#PUT
#MyOwnAnnotationForAdditionalPropInSwagger(value = "Some text")
#Path( "/{carId}" )
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(
value = "Updates car info"
)
public Response patchItem(#ApiParam(value = "Fields to update") Car item) {
/*some code*/
}
After that probably I should extend some class from swagger-core and specify to scan my annotation (#MyOwnAnnotationForAdditionalPropInSwagger).
As result I want to see additional column in swagger ui with my text.
How I can realize it? What class I need to extend?
The swagger 2.0 supports custom fields, there was a Pull Request for this back in 2013 (https://github.com/swagger-api/swagger-node/pull/47).
While apparently it's easy to add the custom fields, since they are not present in the Swagger 2.0 spec, Swagger-UI won't display them by default.
For this to work you will have to change a couple of things.
Implement the desired annotation in your parser implementation (ie. swagger-core or swagger-php) if it doesn't exist.
Clone and modify swagger-ui to display your custom field as you wish.
Note that by doing this you will in fact violate the swagger json schema (https://github.com/swagger-api/swagger-spec/blob/master/schemas/v2.0/schema.json) and any third party validators you may use will fail.
I believe what you are trying to do ca be achieved extending the swagger core reader as described in swagger documentation. Here is an example in one of my projects.

Converting #RequestBody to an object

Guys, Well I have done enough research still I can't find the solution to this.
In a nutshell, I'm simply passing url encoded form data to the Controller method and trying to convert it as a domain object which has Date and integers.
#RequestMapping(value = "/savePassport", method = RequestMethod.POST)
public #ResponseBody
AjaxResponse savePassport(#RequestBody StaffPassport passport, HttpServletResponse response) {
// Some operations.
}
The Staff Passport looks like this:
import java.sql.Date;
public class StaffPassport {
private int staffId;
private String passportNumber;
private String placeOfIssue;
private Date issueDate;
private Date expiryDate;
private String spouseName;
private String oldPassportRef;
private String visaInfo;
private String description;
//gets/sets
}
When I invoke the /savePassport, I get unsupported media exception. I guess it's related to casting.
I can't this working right. Of course I can catch individual form data using #RequestParam and manually do the casting but that's not the point of a framework isn't it?
Where am I going wrong? And you are right. I'm a beginner in Spring, but I love it.
Looks like you're using the wrong annotation. #RequestBody is for taking a request that has arbitrary content in its body,such as JSON, some application defined XML, comma separated variables.. whatever. And using a marshaller that you configure in the dispatcher servlet to turn it into objects.
If all you want to do is ask Spring to bind a plain old form post onto the backing object for you, the correct annotation to put on the method parameter is #ModelAttribute.
If you are posting a JSON Object with jQuery and you want Spring to be able to process it with #RequestBody, use JSON.stringify(....) in your data. Here an example:
var data = { "id": 3, "name": "test" }
$.post("processJsonData.html",JSON.stringify(data), function(data){
...
}
);
If you don't use the JSON.stringify() then you will submit the data as form data and Spring will tell you that you have an unsupported media type.
First of all be sure that you have
<mvc:annotation-driven />
in your Spring configuration file. This is mandatory for working with JSOn in SPring MVC.
Second, I recommend you to test wether request to the server has application/json content type. I belive Fiddler2 will help you to do so.
Third, but I'm not sure about it, Try to change Date items in your POJO from SQL type to regular java type.
UPDATE:
just looked at the Form and it seems like your "Accept" HTTP Header should be also application/json. Please test this issue with Fiddler2 as well.
I assume that you are posting JSON and want Spring to convert to StaffPassport. If you are getting an Unsupported media exception, it is because Spring could not figure out an appropriate way to perform the conversion.
For Spring to convert JSON, it needs Jackson -- make sure you have the Jackson jars in your project. If this is a Maven based project you can add the jackson-mapper-asl artifact ID to your pom.xml. This should give you the jackson-mapper and jackson-core jars.
Edit: I should mention that this applies to Spring 3 (I recently ran into this problem). I'm not sure what else is required for previous versions of Spring.
Check into HttpMessageConverter interface and its implementations. You could write your own implementation of it to convert it to the domain model you want. By the time the control gets to your method, you can access it as if your domain model object is passed.
Ok, I think I should refine my answer. I do not have direct experience of using it in a spring-mvc project but spring-integration. I am pretty sure the applicable media type (application/x-url-form-encoded) is already handled and converted to MultiMap by Spring framework; so, retrieve the values from that just like any other map with the key value being your form variable and populate your business model.
HTH.

Categories

Resources