Openapi specificiation to java REST points with enums always upper case - java

I have an openApi spec which includes the following:
MyType:
type: string
enum:
- foo
- baz
which is used as:
"/v1/configuration/{configType}":
get:
operationId: GetConf
parameters:
- name: configType
in: path
required: true
schema:
$ref: "#/components/schemas/MyType"
Java generates the enum as:
public enum ConfigTypePathParamEnum {
FOO("foo"),
BAZ("baz")
Having written a test for the endpoint, i can only access the foo endpoint as "/v1/configuration/FOO" (which returns an http error code 400). What i want is "/v1/configuration/foo" to work.
This question is similar, but not quite the same:
Case Insensitive String parameter in schema of openApi
I am using openapi generator version 5.2.0.

I use spring-boot and that brings Jackson with it.
Jackson has some nice annotations that control serialisation/deserialisation, so all I have to do is add this method to my enum:
#JsonValue
public String toJson() {
return name().toLowerCase().replaceAll("_","-");
}
NB: since we use kebab-case rather than SNAKE_CASE, we also switch dashes for undescores.

Related

JsonIgnore using Open API spec

I use OpenAPI spec to generate Java POJOs. What do I need to specify in Open API yaml to generate the equivalent of below POJO ?
...
#JsonIgnore
public String ignoredProperty;
...
I have the yaml spec as below
openapi: 3.0.0
info:
title: Cool API
description: A Cool API spec
version: 0.0.1
servers:
- url: http://api.cool.com/v1
description: Cool server for testing
paths:
/
...
components:
schemas:
MyPojo:
type: object
properties:
id:
type: integer
name:
type: string
# I want the below attribute to be ignored as a part of JSON
ignoreProperty:
type: string
the openapi generator supports vendor extensions. Specifically, for the Java generator, it supports the following extensions as of the time of writing. However, an up-to-date list can be found here.
Extension name
Description
Applicable for
Default value
x-discriminator-value
Used with model inheritance to specify value for discriminator that identifies current model
MODEL
x-implements
Ability to specify interfaces that model must implements
MODEL
empty array
x-setter-extra-annotation
Custom annotation that can be specified over java setter for specific field
FIELD
When field is array & uniqueItems, then this extension is used to add #JsonDeserialize(as = LinkedHashSet.class) over setter, otherwise no value
x-tags
Specify multiple swagger tags for operation
OPERATION
null
x-accepts
Specify custom value for 'Accept' header for operation
OPERATION
null
x-content-type
Specify custom value for 'Content-Type' header for operation
OPERATION
null
x-class-extra-annotation
List of custom annotations to be added to model
MODEL
null
x-field-extra-annotation
List of custom annotations to be added to property
FIELD
null
x-webclient-blocking
Specifies if method for specific operation should be blocking or non-blocking(ex: return Mono<T>/Flux<T> or return T/List<T>/Set<T> & execute .block() inside generated method)
OPERATION
false
You can use the x-field-extra-annotation vendor extension listed above to add annotations to any field. So, for your example, you can add the following:
openapi: 3.0.0
info:
title: Cool API
description: A Cool API spec
version: 0.0.1
servers:
- url: http://api.cool.com/v1
description: Cool server for testing
paths:
/
...
components:
schemas:
MyPojo:
type: object
properties:
id:
type: integer
name:
type: string
# I want the below attribute to be ignored as a part of JSON
ignoreProperty:
type: string
x-field-extra-annotation: "#com.fasterxml.jackson.annotation.JsonIgnore"

How to make enum field optional in Swagger Codegen Maven plugin?

TLDR: The problem seems to be that in swagger field should be mandatory when it is enum (Unlike java enum fields). I'm wondering if there is a way to make it optional
I'm using swagger to generate some integration api from yaml files
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.3.1</version>
(by default Gson implementation is used in plugin for working with json)
In one of yaml files I have a description of request with a field which is described like this
...
definitions:
MyRequest:
type: object
required:
- field1
- field2
properties:
myEnumField:
type: string
enum:
- A
- B
- C
Or see documentation for example.
For that swagger generates public static class Adapter (by default Gson implementation is used in plugin for working with json, so this Adapter extends com.google.gson.TypeAdapter). And this implementation forbid to leave this field empty (fails with NPE in runtime otherwise).
I want to permit optional enum fields for all yaml files, or at least for specified ones.
Thanks in advance

How to define date example in MicroProfile OpenAPI

I tried to create minimal example of the problem.
Let's say we have simple return object:
public class Result {
#Schema(example = "2012-01-01")
private LocalDate sampleDate;
// omitted getter and setter
}
returned by simple JAX-RS endpoint:
#Path("/example")
#Produces(MediaType.APPLICATION_JSON)
public class Resource {
public List<Result> example() {
// omitted implementation
}
}
MicroProfile OpenAPI in Open Liberty will automatically generate following OpenAPI (Swagger) file:
openapi: 3.0.0
info:
title: Deployed APIs
version: 1.0.0
servers:
- url: http://localhost:9080/api
paths:
/example:
get:
operationId: example
responses:
default:
description: default response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Result'
components:
schemas:
Result:
type: object
properties:
sampleDate:
type: string
format: date
example: 2012-01-01
The problem is that embedded Swagger UI is displaying the date example as empty JS object:
I'm not sure if this is bug on Swagger UI side because if I don't provide any example in Java annotation = any example in OpenAPI file it will render the example as current day, e.g.:
[
{
"sampleDate": "2018-11-27"
}
]
Everything works correctly when I edit the OpenAPI output manually. Both single and double quotes fix the problem:
...
sampleDate:
type: string
format: date
example: '2012-01-01'
or
...
sampleDate:
type: string
format: date
example: "2012-01-01"
will produce expected output:
[
{
"sampleDate": "2012-01-01"
}
]
Question is how to change the annotations to get desired OpenAPI output.
Single quotes are automatically escaped:
#Schema(example = "'2012-01-01'")
private LocalDate sampleDate;
will produce:
...
sampleDate:
type: string
format: date
example: '''2012-01-01'''
Additional double quotes in Java doesn't have any effect on ouput:
#Schema(example = "\"2012-01-01\"")
private LocalDate sampleDate;
will produce same unquoted output:
...
sampleDate:
type: string
format: date
example: 2012-01-01
I know that I can write the OpenAPI yaml output manually but that is my last resort because I don't want to sacrifice automatic generation just because date examples are not behaving as I want. Maybe some OASFilter can be implemented to automatically wrap date's example values or I'm just missing something obvious here.
I've confirmed the behaviour that you're describing.
It the issue with Swagger-UI which is packaged with Microprofile OpenAPI, you could open issue here:
Swagger UI GitHub.
The value produced, without quotes is completely valid yaml, so UI
should be able to parse it as is.

Serialize a UUID as canonical hex string in JSON using JSON-B

UUID
A universally unique identifier (UUID) is a 128-bit value. Represented in Java by the java.util.UUID class.
Hex string
For display and for serialization, it is canonically formatted as a 36-character hexadecimal string arranged in five groups delimited by a hyphen. For example:fd95cb46-8ec3-11e8-9eb6-529269fb1459
When serializing using the Java-standard XML & JSON APIs I expect this hex string. Worked for XML, but failed for JSON. I am using no annotations of any kind for either XML or JSON. My simple POJO knows nothing of XML nor JSON.
XML = success 👍
When I produce XML using the standard XML-binding framework of JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0, success. I get the hex string as expected. See last element of this snippet:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<panel>
<connected>3.4kVA</connected>
<fedFrom>PANEL 'EHE1' & ATS-EM</fedFrom>
<grounding>ground bus</grounding>
<id>89d14b92-35ae-4c0c-b61d-ea8dbdeb324b</id>
JSON = fail 👎
When I run that same panel object through the standard JSON-binding framework of JSR 367: JavaTM API for JSON Binding (JSON-B), failure. Instead of the expected hex string, I get numbers.
{"connected":"3.4kVA","fedFrom":"PANEL 'EHE1' & ATS-EM","grounding":"ground bus","id":{"leastSignificantBits":-5323841289984462261,"mostSignificantBits":-8515942329042973684},
If you scroll over, you will see the UUID named id is presented as a pair of numbers rather than as a hex string:
"id":{"leastSignificantBits":-5323841289984462261,"mostSignificantBits":-8515942329042973684}
Is there some way to get the JSON binding to behave as the XML binding does? I want the hex string, not a pair of 64-bit numbers.
And of course this marshaled value should work when unmarshaled, re-hydrated into a Java object.
The JSON-B spec makes no mention of the UUID type, so it's up to the implementation whether or not it provides a (de)serializer out of the box. However, if you are using Eclipse Yasson (the JSON-B ref impl), it does provide a UUID (de)serializer by default. I'm not sure what other JSON-B impls (such as Apache Johnzon) provide by default.
If you are using Yasson, I would recommend opening a bug on their GitHub repo, because this should work.
Custom way
If you are using a JSON-B implementation that does not provide UUID adapters by default, you can create and register your own type adapter:
public static class MyUUIDAdapter implements JsonbAdapter<UUID, String> {
#Override
public String adaptToJson(UUID obj) throws Exception {
return obj.toString();
}
#Override
public UUID adaptFromJson(String obj) throws Exception {
return UUID.fromString(obj);
}
}
The easiest way to register the adapter is when you create the Jsonb instance:
Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new MyUUIDAdapter()));
However, if you don't control instantiation of your Jsonb instance (e.g. JAX-RS is doing it under the covers) you can annotate the field/method to use the adapter on:
public class Panel {
#JsonbTypeAdapter(MyUUIDAdapter.class)
public UUID id;
}

How to represent fields with generic types like List<Something> in swagger-spring-mvc for swagger-codegen

I'm using swagger-spring-mvc 0.9.5 and have fields like this in my response data:
#ApiModelProperty("Some description")
private List<Account> accounts;
Short version of the question: how can I get from this annotated Java to e.g. Objective C via swagger-codegen?
The swagger JSON that gets generated by that is:
accounts: {
description: "Some description",
items: {
type: "Account"
},
required: false,
type: "List"
}
My colleague is feeding this into swagger-codegen to generate Objective C classes, and it's producing code that doesn't compile.
#property (nonatomic, strong) NSArray<Optional, NSArray> *accounts;
because NSArray (inside the < >) isn't a protocol.
The swagger template files (mustache) create a protocol for each model. When that protocol is specified on an array, it is picked up by JSONModel to generate the correct models from the data inside the list / array. So in this case the expected output is
#property (nonatomic, strong) NSArray<Optional, MAAccount> *accounts;
This will create an NSArray of MAAccount's (Account being the object type and MA being a prefix that swagger already has).
If we hand-edit the swagger JSON to change List to array (as suggested in various similar cases), the output is correct, but we want to avoid this manual step.
So I tried to get swagger-spring-mvc to use "array":
#ApiModelProperty(value = "Some description", dataType = "array")
private List<Account> accounts;
But then discovered that dataType is ignored in swagger-spring-mvc 0.9.5, and by the looks of it, in springfox 2.0 it is ignored unless it's a fully-qualified Java class name.
Is there a way to achieve this, either by getting swagger-spring-mvc/springfox to use "array" or by any other means?
For the most part the swagger annotations are only an aid to the springfox engine to infer additional information about the types like description/hidden/readonly etc that are not otherwise available from the type system. It can also used as a crutch to represent types that are not easily inferred. Data types can be overriden, but just for type safety as it was pointed out in the comment.
Specifically, I read that dataType will be ignored unless it's a fully-qualified class name.
Like #CupawnTae suggested, version 2.x of springfox supports an option to render generic types with code-generation friendly and language agnostic representations of generic types.
When creating/configuring your docket you will need to specify that the rendered swagger service description needs to be code-generation friendly using the forCodeGeneration option
#Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
...
.forCodeGeneration(true)
...;
}
This will cause springfox to render generic types like List<String>
as ListOfString when forCodeGeneration is set to true
as List«String» when forCodeGeneration is set to false
You can try notation below. Dont't forget to use package info of you class
#ApiModelProperty(dataType = "[Lyour.package.Account;")
private List<Account> accounts;

Categories

Resources