Swagger - customize example request body - java

I have a swaggerized Spring MVC endpoint for a POST operation. The operation takes a path param and a (json) request entity. When the swagger UI is generated, it automatically creates an example value of the request body data type. This example is based on a java entity in the application. The entity is used for some other operations, however for the POST operation, I do not want some of the entity fields exposed in the example. Is it possible to modify this example without modifying the existing java model? For example, is it possible to exclude in the below example lastUpdate.

Yes it is possible to ignore lastUpdate in the example value using jackson annotations JsonIgnore.
import com.fasterxml.jackson.annotation.JsonIgnore;
public class Phone {
private String phoneNumber;
private String lastUpdate;
private int status;
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
#JsonIgnore
public String getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate() {
this.lastUpdate = lastUpdate;
}
public int getStatus() {
return lastUpdate;
}
public void setStatus() {
this.status = status;
}
}

Related

Configure how Springfox Swagger orders properties?

In my Spring Boot rest api, I have the following class:
#Entity
#Table(name="Items")
#JsonPropertyOrder({ "itemId", "description", "viewed" })
public class Item {
#ApiModelProperty(notes="Id of the item.", required=true, value="100000")
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#JsonProperty(access=Access.READ_ONLY)
private int itemId = 0;
#ApiModelProperty(notes="Item description.", required=true, value="Item1")
#NotNull
#Size(min=1, max=256)
private String description;
private int viewed;
public int getItemId() {
return this.itemId;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public int getViewed() {
return this.viewed;
}
}
When I execute the request, the JsonPropertyOrder is respected, however, in the Swagger UI (and the Swagger doc), the properties are listed as description, itemId, viewed. I.e. alphabetical. I never turned on alphabetical sorting, so not sure why its doing that... any way to turn that off? It's doing that to all my classes which are laid out in common sense / logical order...
You can define the order in which the properties are going to be shown with ApiModelProperty#position.
Example:
class MyClass {
#ApiModelProperty(position = 0)
String myFirstProperty;
#ApiModelProperty(position = 1)
String mySecondProperty;
}
It's not the most convenient method, but I couldn't find any other way to achieve this...

How to ignore JSON field in response alone in java

I want to exclude name and age from my response, but When I receive the JSON payload request I need name and age field - after my business logic, I want to send status and message as part of JSON response. name and age should exclude from that. How can I achieve this in java?
public class Sample {
private String name;
private String age;
private String status;
private String message;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
My Controller class:
#PostMapping(path = "/testApp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> test(#RequestBody Sample sample) {
Sample response = myService.calculate(sample);
return new ResponseEntity<Object>(response, HttpStatus.OK);
}
My Request
{
"name": "Mark",
"age": "48"
}
My Response
{
"status": "200",
"message": "success"
}
Using Jackson for Java/JSON serialization and deserialization provides a number of ways to control the JSON that is produced and accepted.
Since you want to omit fields in certain cases, the most straightforward way to do this is with the #JsonIgnore annotation.
#JsonIgnore can be used on fields, getters, and setters (and more) to always ignore the field, ignore on output to JSON, or ignore on JSON->Java deserialization.
Your basic Sample class could ignore message all the time (both when serializing and deserializing) by annotating the field:
public class Sample {
private String name;
private String age;
private String status;
#JsonIgnore private String message;
}
When you want to omit a field when serializing Java -> JSON you can annotate the getter, when you want to ignore a field when deserializing JSON -> Java you annotate the setter.
So if you want to omit name and age when your Sample object is producing JSON, you'd annotate both those fields
public class Sample {
private String name;
private String age;
private String status;
private String message;
#JsonIgnore // Added Annotation
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#JsonIgnore // Added Annotation
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
With those annotations, name and age will be set in the object when you deserialize from JSON, but they will not be output when serializing to JSON, and you need only one class, not separate classes for the request and the response.
I think you should create a separate class for request and response, you can't include two different functionalities in the same class, let's suppose in future in you need to include something in request or response, then again you need to change whole lot of code and if you keep segregation then it will be not a problem.
You can't do it without some tricky hacks. Response and Request don't even share a single field, and from OOP perspective they are different objects, so why mashing them up together?
If you are just experimenting with (de)serialization, then you can try #JsonIgnore on specific setters and getters to manipulate serialization and deserialization. Check this question Ignoring property when deserializing
If you are actually trying to solve the problem writing a clean code then split them into two separate classes.
You should have a Sample class with the name and age fields and a SampleResponse class with only the fields you want to include in the response.

Constructor annotated with Jackson #JsonCreator not being called in POJO?

I am working with a web service that stores POJOs in a MongoDB. I want to make use of Mongo's 'expireAfterSeconds' time to live feature, to clear out old documents in my collection after a certain period of time.
Initially I had an implementation that sent the date to the REST service using the following JSON:
{
"testIndex": "testIndex",
"name": "hello",
"date": "2016-05-09T11:00:39.639Z"
}
The above code created the document in the collection, and with the following annotation, deleted the document after 10 seconds.
#Indexed (expireAfterSeconds=10)
private Date date;
After implementing this code, I decided I wanted to generate the date only on the Java side, meaning the JSON is now as follows:
{
"testIndex": "testIndex",
"name": "hello"
}
Then I have a constructor in the POJO using JsonCreator from Jackson
#JsonCreator
public TTLTestVO (#JsonProperty("testIndex") String testIndex, #JsonProperty("name") String name) {
this.testIndex = testIndex;
this.createdAt = new Date();
this.name = name;
}
From reading the documentation here I believe this should flag the constructor to be used when creating a new object. The testIndex and name fields are populated as before. However with this implementation, each time I check the document in my mongo the date value is 'null'. If I change the text for one of the string values to 'hello from the constructor', the constructor appears not to be called as the initial text contained in the JSON is what is added to the database.
POJO
`
#Document(collection = "test")public class TTLTestVO {
#Id private String _id;
#Indexed
private String testIndex;
#Indexed (expireAfterSeconds=10)
private Date createdAt;
private String name;
#JsonIgnore
public TTLTestVO() {
// default
}
#JsonCreator
public TTLTestVO (#JsonProperty("testIndex") String testIndex, #JsonProperty("name") String name) {
this.testIndex = "hello from the constructor";
this.name = name;
}
public String getId() {
return _id;
}
public void setId(String _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTestIndex() {
return testIndex;
}
public void setTestIndex(String testIndex) {
this.testIndex = testIndex;
}
public Date getDate() {
return createdAt;
}
public void setDate(Date date) {
this.createdAt = date;
}
`
After investigating some more I discovered the issue lies with the Spring Framework implementation of #JsonCreator - I removed the imports for org.springframework.cloud.cloudfoundry.com.fasterxml.jackson.annotation and replaced them with com.fasterxml.jackson.annotation. The above implementation now functions as expected.
I have been unable to find an explanation online as to why the spring version isn't working, so if anyone has any ideas please let me/ others know

How to apply Single annotation on multiple variables?

I am rookie in Java Annotation and have been searching for applying single annotation on multiple variable simultaneously.
Code:
#Document(collection = "users")
public class User {
private ObjectId id;
#NotNull
private String email;
private String imageURL;
private String authToken;
private Date createdDate;
private Date updateDate;
private boolean isActivated;
private int credits;
.....getter/Setter Method
I want to apply #NotNull property on email, imageURL and authToken too. I can do it by writing #NotNull to each variable but not preferring. How to do it?
#NotNull annotation can be applied at element not at group of elements.
JavaDoc: The annotated element must not be null. Accepts any type.
If you really want to get away with boiler plate code, you can use frameworks like Lombok which can help you to certain extent.
Link : http://projectlombok.org/features/Data.html
OR you can use reflection to validate all the method.
for (Field f : obj.getClass().getDeclaredFields()) {
f.setAccessible(true); // optional
if (f.get(obj) == null) {
f.set(obj, getDefaultValueForType(f.getType()));
// OR throw error
}
}
Java does not support multiple annotation of this type. But you can write something like this
Create a class with annotated field.
Create setters and getters to access the field.
Create all your name,email field as instance of this class.
This way fields will implicitly annotated as NotNull.
public class NotNullString {
#NotNull
String str;
public void set(String str)
{
this.str = str;
}
public String get()
{
return this.str;
}
}
NotNullString name;
NotNullString email;

Partially deserialize a json object in a restful post call

I am trying to get a method in springmvc to accept a partial json string of an object, and have jackson automatically de-serialize it for me.
I can solve it by making a temporary object with only the attributes I want, or pass it in as a string and use Gson to desearialize it for me, but these feel hacky. Is there any way to tell jackson how to do it?
Here is the controller snippet:
#RequestMapping(value = "/task",
method = RequestMethod.POST,
consumes="application/json")
public #ResponseBody String postTask(#RequestBody Task task){
if(task.getId() == null){
task.setId(UUID.randomUUID());
}
if(task.getDate_entered() == 0){
task.setDate_entered(System.currentTimeMillis());
}
TaskDao.addTask(task);
return "success";
}
And the task, a basic pojo:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class Task {
private UUID id;
private String name;
private String description;
private long date_entered;
private long finish_by;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
// Rest of the getters and setters
}
If you can't tell by my other spring related questions, I'm kind of flying blind, and can't figure out the proper google query for this one.
Thanks!
You need to use #JsonIgnoreannotation of jackson on the method (on setter for deserialization and on getter for serialization) or field, for which you want to ignore serialization and/or deserialization. e.g.
In your example, if you don't want to serialize description, then you can do,
#JsonIgnore
public void setDescription(String description) {
this.description = description;
}
And you will see, that you won't get value of description in converted model.

Categories