Swagger-annotation generation - java

I have a problem generating a swagger.json file with swagger annotations. The problem is with the generation of map with array.
Ex:
I have an #ApiModel with a field:
#JsonProperty
private Map<String, String[]> example;
When it generates it looks like this:
"example" : {
"type" : "object",
"additionalProperties" : {
"$ref" : "#/definitions/Array"
}
}
"Array" : {
"type" : "object"
},
When I create my client class with swagger-codegen based on the generated json, it resolve to:
private Map<String, Array> example = new HashMap<String, Array>();
But Array doesn`t exist.
Based on what I`ve seen, the json should look like this:
"definitions": {
"example": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
Is there anyway to make it works ?
I use: Dropwizard, Jersey2, Swagger, JAX-RS

Related

JSON-Simple. Modify and use complex object

I am using the JSON-simple library to parse the Json format. How can I use or modify something to a JSONArray? For e.g. consider the following json
"Place": [
{
"name": "owner 1"
},
{
"name": "owner 2"
}
],
"branch": [
{
"name": "sucursal",
"employe": [
],
"clients": [
]
},
I need to add some clients and in the future modify them. How to achieve this?
Simply create a pojo class in the same format.
Classs Pojo{
private List<Place> place;
private List<Branch> branch;
// other fields
}
and use writeValueAsString() from your object mapper to convet it to json.

How to generate JsonSchema As Array from Java Class

I'm generating JsonSchema from Java class using fasterxml.jackson.
The generated Jsonschema will be as below
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
My code to generate JsonSchema
public static String getJsonSchema(Class definitionClass) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper().disable(
MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS);
JavaType javaType = mapper.getTypeFactory().constructType(definitionClass);
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
JsonSchema schema = schemaGen.generateSchema(javaType);
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
}
I tried to use ArraySchema arraySchema = schema.asArraySchema(); but it generates invalid schema.
My expected JsonSchema should be like below
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
TL;DR: Call getJsonSchema(MyClass[].class)
Works fine if we simply tell it to generate the schema of a Java array.
To demo, I created a MyClass class fitting the shown schema. I used public fields for simplicity of the demo, but we'd use private fields and public getter/setter methods in real life.
class MyClass {
public String id;
public String name;
}
Now, to show that we get the same result as in the question, we call it with MyClass.class:
System.out.println(getJsonSchema(MyClass.class));
Output
{
"type" : "object",
"id" : "urn:jsonschema:MyClass",
"properties" : {
"id" : {
"type" : "string"
},
"name" : {
"type" : "string"
}
}
}
Now, we want the schema to be an array of those, so we will instead call it using MyClass[].class.
System.out.println(getJsonSchema(MyClass[].class));
Output
{
"type" : "array",
"items" : {
"type" : "object",
"id" : "urn:jsonschema:MyClass",
"properties" : {
"id" : {
"type" : "string"
},
"name" : {
"type" : "string"
}
}
}
}
The above was tested using jackson-module-jsonSchema-2.10.3.jar.

Swagger Documentation when the java class is deserialised from String input

In my request body, I have a field which takes a string as input but is converted into a java object while deserializing.
public class UserCredentials {
#NotBlank String username;
#NotNull ReferenceString passwordRef;
}
the passwordRef value is taken as string and I used #JsonCreator to convert the string to ReferenceString object.
public class ReferenceString {
private String identifier;
private String type;
#JsonCreator
public ReferenceString(String secretRefConfigString) {
// logic to break the string into two and set the
// identifier and type value
return;
}
The serialization and deserialization work fine. I am having an issue with the swagger documentation, the documentation looks like
"UserCredentials" : {
"type" : "object",
"required" : [ "passwordRef" ],
"properties" : {
"username" : {
"type" : "string"
},
"passwordRef" : {
"$ref" : "#/definitions/ReferenceString"
}
}
}
"ReferenceString" : {
"type" : "object",
"properties" : {
"identifier" : {
"type" : "string"
},
"type" : {
"type" : "string"
}
}
}
Since the API will take a string as input, I want that in the docs the type of passwordRef should be shown as String and not ReferenceString, also I don't want the user to see the internal class ReferenceString.
I read about #ApiModel and #ApiModelProperty. I can use the #ApiModelProperty on my fields and the documentation will show that field as a string, but in my code, a lot of fields will be of type ReferenceString and I don't want to use #ApiModelProperty on every field.
Can it be done easily some different way? Can I add some annotation/code only on the ReferenceString to solve this issue?

Spring Hateoas / HAL throw Exception

I've got weird issue because everything works fine in my application, by after do GET method I always get exception:
2018-05-10 12:17:18.608 WARN 16031 --- [nio-8080-exec-1] tion$ResourceSupportHttpMessageConverter : Failed to evaluate Jackson serialization for type [class com.computeralchemist.domain.components.OpinionDto]: java.lang.IllegalStateException: Cannot override _serializer: had a `org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListSerializer`, trying to set to `org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$NestedEntitySerializer`
My DTO object is simple:
#Getter
#Setter
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public abstract class ComputerComponent extends ResourceSupport {
....
}
And one of child class:
#Getter
#Setter
#Document(collection = "cpu")
public class Cpu extends ComputerComponent {
#Id
private long productId;
private CpuParameters cpuParameters;
}
And REST controller's method:
#GetMapping(value = "/{id}", produces = "application/json; charset:UTF-8")
#ResponseStatus(HttpStatus.OK)
public ComputerComponent getComponent(#PathVariable("component") String component,
#PathVariable("id") long id) {
ComputerComponent computerComponent = repositoryProvider.findComponent(component, id);
if (computerComponent == null)
throw new ComponentNotFoundException(component, id);
computerComponent.add(linkTo(methodOn(ComponentsController.class)
.getComponent(component, id)).withSelfRel());
computerComponent.add(linkTo(methodOn(ComponentsController.class)
.getListOfComponents(computerComponent.getComponentType().toString()))
.withRel("collection"));
return computerComponent;
}
Json returned (looks correctly, but I don't want null values):
{
"componentType" : "cpu",
"producent" : "AMD",
"model" : "Ryzen 5 1600",
"content" : [ ],
"links" : [ ]
},
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/components/cpu/1",
"hreflang" : null,
"media" : null,
"title" : null,
"type" : null,
"deprecation" : null,
"content" : [ ],
"links" : [ ]
}, {
"rel" : "collection",
"href" : "http://localhost:8080/components/cpu",
"hreflang" : null,
"media" : null,
"title" : null,
"type" : null,
"deprecation" : null,
"content" : [ ],
"links" : [ ]
} ]
}
PS: Why in Links property is "hreflang","media" etc?
This answer is here not so much because it is the answer to the OP's problem (which they seem to have solved) but because it is what caused the problem for me. So maybe someone else searching for this will be helped...
It appears that if you have:
'org.springframework.boot:spring-boot-starter-hateoas'
then you have to remove
'org.springframework.boot:spring-boot-starter-data-rest'
At least - that is what solved the problem for me. The exception went away, as did the null fields that the OP reported.

How To Use Jackson's #JsonIdentityInfo for Deserialization of directed Graphs?

I want to use Jackson 2.3.3 for Deserialization/Serialization of directed graphs. The structure I came up with is roughly the following:
public Class Graph {
private final Set<Node> nodes;
public Graph(Set<Node> nodes) { ... }
public Set<Node> getNodes() { ... }
}
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "name")
public Class Node {
private final String name;
private final Set<Edge> edges;
public Node(String name, Set<Edge> edges) { ... }
public String getName() { ... }
public Set<Edge> getEdges() { ... }
}
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "name")
public Class Edge {
private final String name;
private final Node successor;
public Edge(String name, Node successor) { ... }
public String getName() { ... }
public Node getSuccessor() { ... }
}
And I expect to have this JSON-Structure:
{
"graph": [{
"name": "A",
"edges": [{
"name": "0",
"successor": "B"
}, {
"name": "1",
"successor": "A"
}]
}, {
"name": "B",
"edges": [{
"name": "0",
"successor": "A"
}, {
"name": "1",
"successor": "B"
}]
}]
}
But I get the following error while deserialization (even with annotation #JsonProperty("name") at the Getters):
com.fasterxml.jackson.databind.JsonMappingException: Invalid Object Id definition for some.package.graph.Node: can not find property with name 'name'
I have found some solutions for Jackson 1.6 with Back-Reference Annotations, but I'd like to use the new Jackson 2.x Annotation, as it was advertised so much in the API Update from 1.9 to 2.0 of Jackson.
What point am I missing here? Thanks for constructive answers in advance.
EDIT
(Removed my answer from here to the Answer section)
I got kind of blind of staring too long at it. Here's what's gone wrong:
The Serialization actually worked as intended. What didn't work was the Deserialization, because Jackson wasn't able to instantiate my Node-Object. I simply forgot to annotate the parameters of the constructor methods correctly.
I was now facing another problem. The generated JSON now looked like this:
"graph": {
"nodes": [{
"name": "B",
"edges": [{
"label": "1",
"successor": "B"
}, {
"label": "0",
"successor": {
"name": "A",
"edges": [{
"label": "1",
"successor": "A"
}, {
"label": "0",
"successor": "B"
}]
}
}]
}, "A"]
}
So far so good. But during mapping, Jackson confronts me with this Error:
java.lang.IllegalStateException: Could not resolve Object Id [B] (for [simple
type, class some.package.graph.Node]) -- unresolved forward-reference?
I even changed the Label of the edges because I thought the same property name might confuse Jackson here, but that didn't help either...
My guess here is that Jackson can't reference the Node B, because it is still being constructed (you could say it is actually some kind of root in this example). The only way to fix this seems to construct all the Nodes without the edges and inject them in a second step.

Categories

Resources