OpenAPI springboot generator does not set default value for nullable fields in models - swagger-codegen

When I create models using openAPI generator for springboot, the default value for nullable fields is not being set in models. Is there a way to get it generated with the default value present ?
MyModel:
type: object
properties:
data1:
type: integer
format: int32
default: 10
nullable: true
This generates a java class as -
public class MyModel {
#JsonProperty("data1")
private JsonNullable<Integer> data1 = JsonNullable.undefined();
I would expect it to create it as JsonNullable.of(10) instead so that the default value is used.

Related

YAML anchor label duplicates the key property of the anchored object

I use beans annotated with JAXB and the Jackson's JaxbAnnotationModule and YAMLFactory to export my objects to YAML.
public class Account {
#XmlID
protected String name;
public class Subtask
#XmlIDREF
protected Account account;
In the resulting YAML the account name is duplicated:
accounts:
- &JWFFTP name: "JWFFTP"
...
- &BREEZEFTP name: "BREEZEFTP"
...
...
Is it possible to tell Jackson to omit the property "name" from the YAML and when parsing it back, fill the value of "name" from the anchor label? Desired:
accounts:
- &JWFFTP ...
- &BREEZEFTP ...
...
Or the opposite, disable the use of YAML anchors and during the deserialization use the "name" property to lookup the value of the Subtask.account

Django rest framework - model serializer doesn't serialize all fields

I'm using Django rest framework 3.7.7
I want to serialize an object instance and then deserialize it (without saving to DB again).
So I created a serializer that inherits from serializers.ModelSerializer.
To this model instance I sometimes add a field within the request that is not part of the model, using property setter. I did add it to the serializer as well, but when serializing - I don't see that field in the serialized data.
This is the model:
class MyModel(models.Model):
manager = models.CharField(max_length=200)
reviewer = models.CharField(max_length=200)
#property
def note(self):
return getattr(self, '_note', None)
#note.setter
def note(self, value):
self._note = value
This is the model serializer:
class MyModelSerializer(serializers.ModelSerializer):
note = serializers.CharField(write_only=True, required=False, max_length=1000, allow_null=True)
class Meta:
model = MyModel
fields = [
'manager',
'reviewer',
'note'
]
This is how I use the serializer:
ser_instance = MyModelSerializer(self.instance)
ser_data = ser_instance.data
seems like the ser_instance.data contains only the model fields data (without the 'note')
From the write_only--[DRF-Doc], it states that
Set this to True to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.
Defaults to False
So, if you need to serialize the note field, remove the write_only=true from serializer.
#serializers.py
class MyModelSerializer(serializers.ModelSerializer):
note = serializers.CharField(required=False, max_length=1000, allow_null=True) # removed "write_only=True"
...

Use Swagger/OpenAPI discriminator so that Jackson serializes object correctly

We're having trouble using the OpenAPI 2.0 discriminator in way that makes both the Swagger tools and the Jackson serializer happy.
Problem: during serialization Jackson currently generates two JSON properties for the discriminator, one of them having a null value.
OpenAPI 2.0 definition
swagger: '2.0'
info:
version: v1
title: Error API
paths:
/errors:
get:
description: Stack Overflow test
responses:
'200':
description: OK
schema:
$ref: '#/definitions/SpecificError'
definitions:
GeneralError:
description: Error Base Structure
type: object
discriminator: errorType
properties:
errorType:
type: string
message:
type: string
required:
- errorType
SpecificError:
description: Test
allOf:
- $ref: "#/definitions/GeneralError"
AFAIU the discriminator is correctly defined. The spec requires it to be listed both in the properties and the required list.
The property name used MUST be defined at this schema and it MUST be in the required property list. When used, the value MUST be the name of this schema or any schema that inherits it.
Swagger codegen
What the Swagger Java codegen produces is this:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "errorType",
visible = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = SpecificError.class, name = "SpecificError"),
})
public class GeneralError {
#JsonProperty("errorType")
private String errorType = null;
// accessors, even for errorType!, follow here
The accessors for errorType come as a big surprise. As the field is only needed during serialization & deserialization regular client code shouldn't have access to it. One could even argue that the field shouldn't be there at all.
Jackson serializer
As a simple test bed I use this
SpecificError specificError = (SpecificError) new SpecificError().message("message")
ObjectMapper objectMapper = new ObjectMapper();
ObjectWriter writer = objectMapper.writer();
writer.writeValue(System.out, specificError);
This produces {"errorType":"SpecificError","message":"message","errorType":null}.
-> errorType appears twice
Q: whose fault is it? Is my Swagger definition wrong? Should the Swagger Java codegen not generate private String errorType? Or should Jackson be able to deal with this i.e. recognize that its #JsonTypeInfo and the property of that name are actually the same thing?

Jackson deserialization: How to get a default value even if the JSON property was null

In my project I'm using Jersey 2.23.1 with Jackson for JSON support.
When I'm getting a request with something like { "foo":null, "bar":"123" } as JSON, matching with class A{String foo; String bar;} Jersey first creates and instance of A (with default values if specified in constructor), then deserialize JSON to a temporary object A', then copies all JSON fields that were specified in JSON from A' to A. If I have default values in A-class constructor, and have fields equal to null in JSON, all my default values are erased and replaced by null. So in the example above, if I have a default value for the foo field, it will be replaced by null in the object Jersey will return as param for my #Path annotated method.
I'm using #JsonInclude(Include.NON_NULL) on A class to avoid the transfer of null fields during Response. But it only works for serialization, what about deserialization? I mean, when having { "foo":null } as JSON results in field "foo" = null in new object instance after deserialization.
Here is some code to sum all of this :
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(value = Include.NON_NULL)
public class User {
public enum EUserRole {
PARENT, STUDENT, PROF, ADMIN
}
#Id
public String id;
public String firstName;
public String lastName;
public EUserRole role;
public User() {
id = ObjectId.get().toString();
role = EUserRole.STUDENT;
lastName = "RandomLastName";
}
}
if I'm passing this kind of JSON
{
"id":null,
"lastName":null,
"firstName":"Random First Name",
"role":"STUDENT"
}
to my method (in controller)
#POST
public Response createUser(final User entity) {
}
it results that all null fields in JSON are set to null in my entity and not set to the constructor default values.
Do you know if there is a way to specify Jackson to ignore null fields during deserialization? Or is this a Jersey-related behavior?
There is no way to ignore data from JSON payload in that sense, based on value contained (you can use ignoral to just ignore all values for given property).
So if you want to avoid null assignment, you need define a setter that will just swallow null value (that is, only assign non-null).
Ability to prevent null assignment might a useful feature to add via #JsonFormat.Feature, something like:
// hypothetical no such feature exists yes
#JsonFormat(without = JsonFormat.Feature.ALLOW_NULL_ASSIGNMENT)
so perhaps this could be a feature request.
And the reason I think this belongs to per-property handling is that this seems like a specific rule for some of the properties. Although perhaps there could also be a matching global setting if it seems users really like such null-ignoral.

how to hide field during serialization (but not deserialization)

In our project (springMVC) Rest API project I wish to only use ONE model for both request and response (to avoid having to add tons of code to copy field from object to object)
I'd like to use Swagger to handle all the doc, but I'm running into a little problem. For example let say I have a model User
public class User {
private Long id;
private String username;
private String password;
}
And a simple controller
public void createUser(#RequestBody User user)...
public User getUser(Long id) ..
Now I would like swagger to hide the property password on deserialization but not serialization (so having it display for the Input but the output)
and the opposite for the Id field.
I have tried using #JsonIgnore coupled with #JsonProperty but on the swagager-ui it either displays everything or hides everything. I cannot manage to it work.
Could someone indicate me what is the best way of archiving my goal ? Is it possible to use a single model for request and response while using swagger? In case it is not possible to use #JsonIgnore, is there a way to archive this differently ?
Swagger doesn't want you to have different input/output models with the same name. You should simply create an interface and attach that to the input, and for the output extend that interface or add an implementation with the additional field. For example, please see here for modeling tips:
https://swaggerhub.com/api/swagger-tutorials/modeling-samples/1.0.0
Your exact use case is one of them. The solution posted in the above link is here:
definitions:
User:
description: this is a user that would be passed into the system
properties:
username:
type: string
UserResponse:
allOf:
- $ref: '#/definitions/User'
- type: object
required:
- id
properties:
id:
type: string
format: uuid
readOnly: true
where User is the input object, and UserResponse is the output object, with the additional id field.
Add #JsonIgnore with getter of the field and #JsonProperty with the setter or with the field . As Due to use of immutable code or final fields sometime setter doesn't work.
example :
public class Student {
private Float name;
private String rollnum;
private String section;
#JsonProperty
private Boolean passOrFailed;
#JsonIgnore
public Boolean getpassOrFailed {
return active;
}
}
Remember to use both else else it will lead to removing element in deserialization