diff --git a/examples/javalin-maven-java/pom.xml b/examples/javalin-maven-java/pom.xml
index 5a6049e..e27db83 100644
--- a/examples/javalin-maven-java/pom.xml
+++ b/examples/javalin-maven-java/pom.xml
@@ -23,11 +23,14 @@
+
io.javalin
javalin
${javalin.version}
+
+
io.javalin.community.openapi
javalin-openapi-plugin
@@ -43,6 +46,8 @@
javalin-redoc-plugin
${javalin.openapi.version}
+
+
org.webjars.npm
redoc
@@ -54,6 +59,8 @@
+
+
org.tinylog
tinylog-api
@@ -69,6 +76,28 @@
slf4j-tinylog
2.4.1
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.28
+ provided
+
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+ 2.0.2
+
+
+
+
+ org.mongodb
+ bson
+ 4.9.1
+
@@ -80,11 +109,19 @@
3.10.1
+
io.javalin.community.openapi
openapi-annotation-processor
${javalin.openapi.version}
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.28
+
diff --git a/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java b/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java
index 4333929..1abdd22 100644
--- a/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java
+++ b/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java
@@ -4,207 +4,239 @@
import io.javalin.Javalin;
import io.javalin.http.Context;
import io.javalin.http.Handler;
-import io.javalin.openapi.ApiKeyAuth;
-import io.javalin.openapi.BasicAuth;
-import io.javalin.openapi.BearerAuth;
-import io.javalin.openapi.CookieAuth;
-import io.javalin.openapi.HttpMethod;
-import io.javalin.openapi.ImplicitFlow;
-import io.javalin.openapi.OAuth2;
-import io.javalin.openapi.OpenApi;
-import io.javalin.openapi.OpenApiContact;
-import io.javalin.openapi.OpenApiContent;
-import io.javalin.openapi.OpenApiContentProperty;
-import io.javalin.openapi.OpenApiExample;
-import io.javalin.openapi.OpenApiIgnore;
-import io.javalin.openapi.OpenApiInfo;
-import io.javalin.openapi.OpenApiLicense;
-import io.javalin.openapi.OpenApiName;
-import io.javalin.openapi.OpenApiParam;
-import io.javalin.openapi.OpenApiPropertyType;
-import io.javalin.openapi.OpenApiRequestBody;
-import io.javalin.openapi.OpenApiResponse;
-import io.javalin.openapi.OpenApiSecurity;
-import io.javalin.openapi.OpenApiServer;
-import io.javalin.openapi.OpenApiServerVariable;
-import io.javalin.openapi.OpenID;
-import io.javalin.openapi.Security;
-import io.javalin.openapi.plugin.OpenApiConfiguration;
+import io.javalin.openapi.*;
import io.javalin.openapi.plugin.OpenApiPlugin;
-import io.javalin.openapi.plugin.SecurityConfiguration;
-import io.javalin.openapi.plugin.redoc.ReDocConfiguration;
import io.javalin.openapi.plugin.redoc.ReDocPlugin;
-import io.javalin.openapi.plugin.swagger.SwaggerConfiguration;
import io.javalin.openapi.plugin.swagger.SwaggerPlugin;
+import io.javalin.security.RouteRole;
+import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import org.bson.types.ObjectId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.Serializable;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
-import static java.util.Map.entry;
+import javax.validation.constraints.NotEmpty;
/**
* Starts Javalin server with OpenAPI plugin
*/
public final class JavalinTest implements Handler {
+ enum Rules implements RouteRole {
+ ANONYMOUS,
+ USER,
+ }
+
/**
* Runs server on localhost:8080
*
* @param args args
*/
public static void main(String[] args) {
- Javalin.create(config -> {
- String deprecatedDocsPath = "/swagger-docs";
-
- OpenApiContact openApiContact = new OpenApiContact();
- openApiContact.setName("API Support");
- openApiContact.setUrl("https://www.example.com/support");
- openApiContact.setEmail("support@example.com");
-
- OpenApiLicense openApiLicense = new OpenApiLicense();
- openApiLicense.setName("Apache 2.0");
- openApiLicense.setIdentifier("Apache-2.0");
-
- OpenApiInfo openApiInfo = new OpenApiInfo();
- openApiInfo.setTitle("Awesome App");
- openApiInfo.setSummary("App summary");
- openApiInfo.setDescription("App description goes right here");
- openApiInfo.setTermsOfService("https://example.com/tos");
- openApiInfo.setContact(openApiContact);
- openApiInfo.setLicense(openApiLicense);
- openApiInfo.setVersion("1.0.0");
-
- OpenApiServerVariable portServerVariable = new OpenApiServerVariable();
- portServerVariable.setValues(new String[] { "7070", "8080" });
- portServerVariable.setDefault("8080");
- portServerVariable.setDescription("Port of the server");
-
- OpenApiServerVariable basePathServerVariable = new OpenApiServerVariable();
- basePathServerVariable.setValues(new String[] { "v1" });
- basePathServerVariable.setDefault("v1");
- basePathServerVariable.setDescription("Base path of the server");
-
- OpenApiServer openApiServer = new OpenApiServer();
- openApiServer.setUrl("https://example.com:{port}/{basePath}");
- openApiServer.setDescription("Server description goes here");
- openApiServer.addVariable("port", portServerVariable);
- openApiServer.addVariable("basePath", basePathServerVariable);
-
- OpenApiServer[] servers = new OpenApiServer[] { openApiServer };
-
- OpenApiConfiguration openApiConfiguration = new OpenApiConfiguration();
- openApiConfiguration.setInfo(openApiInfo);
- openApiConfiguration.setServers(servers);
- openApiConfiguration.setDocumentationPath(deprecatedDocsPath); // by default it's /openapi
- // Based on official example: https://swagger.io/docs/specification/authentication/oauth2/
- openApiConfiguration.setSecurity(new SecurityConfiguration(
- Map.ofEntries(
- entry("BasicAuth", new BasicAuth()),
- entry("BearerAuth", new BearerAuth()),
- entry("ApiKeyAuth", new ApiKeyAuth()),
- entry("CookieAuth", new CookieAuth("JSESSIONID")),
- entry("OpenID", new OpenID("https://example.com/.well-known/openid-configuration")),
- entry("OAuth2", new OAuth2(
- "This API uses OAuth 2 with the implicit grant flow.",
- List.of(
- new ImplicitFlow(
- "https://api.example.com/oauth2/authorize",
- new HashMap<>() {{
- put("read_pets", "read your pets");
- put("write_pets", "modify pets in your account");
- }}
- )
- )
- ))
- ),
- List.of(
- new Security(
- "oauth2",
- List.of(
- "write_pets",
- "read_pets"
- )
- )
- )
- ));
- openApiConfiguration.setDocumentProcessor(docs -> { // you can add whatever you want to this document using your favourite json api
- docs.set("test", new TextNode("Value"));
- return docs.toPrettyString();
- });
- config.plugins.register(new OpenApiPlugin(openApiConfiguration));
-
- SwaggerConfiguration swaggerConfiguration = new SwaggerConfiguration();
- swaggerConfiguration.setDocumentationPath(deprecatedDocsPath);
- config.plugins.register(new SwaggerPlugin(swaggerConfiguration));
-
- ReDocConfiguration reDocConfiguration = new ReDocConfiguration();
- reDocConfiguration.setDocumentationPath(deprecatedDocsPath);
- config.plugins.register(new ReDocPlugin(reDocConfiguration));
- })
- .start(8080);
+ Javalin.createAndStart(config -> {
+ // config.routing.contextPath = "/custom";
+ String deprecatedDocsPath = "/api/openapi.json"; // by default it's /openapi
+
+ config.registerPlugin(new OpenApiPlugin(openApiConfig ->
+ openApiConfig
+ .withDocumentationPath(deprecatedDocsPath)
+ .withRoles(Rules.ANONYMOUS)
+ .withPrettyOutput()
+ .withDefinitionConfiguration((version, openApiDefinition) ->
+ openApiDefinition
+ .withInfo(openApiInfo ->
+ openApiInfo
+ .description("App description goes right here")
+ .termsOfService("https://example.com/tos")
+ .contact("API Support", "https://www.example.com/support", "support@example.com")
+ .license("Apache 2.0", "https://www.apache.org/licenses/", "Apache-2.0")
+ )
+ .withServer(openApiServer ->
+ openApiServer
+ .description("Server description goes here")
+ .url("http://localhost:{port}{basePath}/" + version + "/")
+ .variable("port", "Server's port", "8080", "8080", "7070")
+ .variable("basePath", "Base path of the server", "", "", "/v1")
+ )
+ // Based on official example: https://swagger.io/docs/specification/authentication/oauth2/
+ .withSecurity(openApiSecurity ->
+ openApiSecurity
+ .withBasicAuth()
+ .withBearerAuth()
+ .withApiKeyAuth("ApiKeyAuth", "X-Api-Key")
+ .withCookieAuth("CookieAuth", "JSESSIONID")
+ .withOpenID("OpenID", "https://example.com/.well-known/openid-configuration")
+ .withOAuth2("OAuth2", "This API uses OAuth 2 with the implicit grant flow.", oauth2 ->
+ oauth2
+ .withClientCredentials("https://api.example.com/credentials/authorize")
+ .withImplicitFlow("https://api.example.com/oauth2/authorize", flow ->
+ flow
+ .withScope("read_pets", "read your pets")
+ .withScope("write_pets", "modify pets in your account")
+ )
+ )
+ .withGlobalSecurity("OAuth2", globalSecurity ->
+ globalSecurity
+ .withScope("write_pets")
+ .withScope("read_pets")
+ )
+ .withGlobalSecurity("BearerAuth")
+ )
+ .withDefinitionProcessor(content -> { // you can add whatever you want to this document using your favourite json api
+ content.set("test", new TextNode("Value"));
+ return content.toPrettyString();
+ })
+ )));
+
+ config.registerPlugin(new SwaggerPlugin(swaggerConfiguration -> swaggerConfiguration.setDocumentationPath(deprecatedDocsPath)));
+
+ config.registerPlugin(new ReDocPlugin(reDocConfiguration -> reDocConfiguration.setDocumentationPath(deprecatedDocsPath)));
+
+ for (JsonSchemaResource generatedJsonSchema : new JsonSchemaLoader().loadGeneratedSchemes()) {
+ System.out.println(generatedJsonSchema.getName());
+ System.out.println(generatedJsonSchema.getContentAsString());
+ }
+ });
}
- private static final String ROUTE = "/main/{name}";
-
- @Override
@OpenApi(
- path = ROUTE,
- operationId = "cli",
- methods = HttpMethod.POST,
- summary = "Remote command execution",
- description = "Execute command using POST request. The commands are the same as in the console and can be listed using the 'help' command.",
- tags = { "Cli" },
- security = {
- @OpenApiSecurity(name = "BasicAuth")
- },
- requestBody = @OpenApiRequestBody(
- content = {
- @OpenApiContent(from = String.class), // simple type
- @OpenApiContent(from = EntityDto[].class), // array
- @OpenApiContent(from = LombokEntity.class), // lombok
- @OpenApiContent(from = KotlinEntity.class), // kotlin
- @OpenApiContent(mimeType = "image/png", type = "string", format = "base64"), // single file upload,
- @OpenApiContent(mimeType = "multipart/form-data", properties = {
- @OpenApiContentProperty(name = "form-element", type = "integer"), // random element in form-data
- @OpenApiContentProperty(name = "reference", from = KotlinEntity.class) // reference to another object
- @OpenApiContentProperty(name = "file-name", isArray = true, type = "string", format = "base64") // multi-file upload
- })
- }
- ),
- headers = {
- //@OpenApiParam(name = "Authorization", description = "Alias and token provided as basic auth credentials", required = true, type = UUID.class),
- @OpenApiParam(name = "Optional"),
- @OpenApiParam(name = "X-Rick", example = "Rolled"),
- @OpenApiParam(name = "X-SomeNumber", required = true, type = Integer.class, example = "500")
- },
- pathParams = {
- @OpenApiParam(name = "name", description = "Name", required = true, type = UUID.class)
- },
- responses = {
- @OpenApiResponse(status = "200", description = "Status of the executed command", content = {
- @OpenApiContent(from = EntityDto[].class)
- }),
- @OpenApiResponse(
- status = "400",
- description = "Error message related to the invalid command format (0 < command length < " + 10 + ")",
- content = @OpenApiContent(from = EntityDto[].class)
+ path = "/main/{name}",
+ methods = HttpMethod.POST,
+ operationId = "cli",
+ summary = "Remote command execution",
+ description = "Execute command using POST request. The commands are the same as in the console and can be listed using the 'help' command.",
+ tags = { "Default", "Cli" },
+ security = {
+ @OpenApiSecurity(name = "BasicAuth")
+ },
+ headers = {
+ @OpenApiParam(name = "Authorization", description = "Alias and token provided as basic auth credentials", required = true, type = UUID.class),
+ @OpenApiParam(name = "Optional"),
+ @OpenApiParam(name = "X-Rick", example = "Rolled"),
+ @OpenApiParam(name = "X-SomeNumber", required = true, type = Integer.class, example = "500")
+ },
+ pathParams = {
+ @OpenApiParam(name = "name", description = "Name", required = true, type = UUID.class)
+ },
+ queryParams = {
+ @OpenApiParam(name = "query", description = "Some query", required = true, type = Integer.class)
+ },
+ requestBody = @OpenApiRequestBody(
+ description = "Supports multiple request bodies",
+ content = {
+ @OpenApiContent(from = String.class, example = "value"), // simple type
+ @OpenApiContent(from = String[].class, example = "value"), // array of simple types
+ @OpenApiContent( // map of simple types
+ mimeType = "application/map-string-string",
+ additionalProperties = @OpenApiAdditionalContent(
+ from = String.class,
+ exampleObjects = {
+ @OpenApiExampleProperty(name = "en", value = "hey"),
+ @OpenApiExampleProperty(name = "pl", value = "hejka tu lenka"),
+ }
+ )
+ ),
+ @OpenApiContent( // map of complex types
+ mimeType = "application/map-string-object",
+ additionalProperties = @OpenApiAdditionalContent(from = Foo.class)
+ ),
+ @OpenApiContent(from = KotlinEntity.class, mimeType = "app/barbie", exampleObjects = {
+ @OpenApiExampleProperty(name = "name", value = "Margot Robbie")
+ }), // kotlin
+ @OpenApiContent(from = LombokEntity.class, mimeType = "app/lombok"), // lombok
+ @OpenApiContent(from = EntityWithGenericType.class), // generics
+ @OpenApiContent(from = RecordEntity.class, mimeType = "app/record"), // record class
+ @OpenApiContent(from = DtoWithFields.class, mimeType = "app/dto-fields"), // map only fields
+ @OpenApiContent(from = DtoWithFieldsAndMethods.class, mimeType = "app/dto-fields-and-methods"), // map fields and methods
+ @OpenApiContent(from = EnumEntity.class, mimeType = "app/enum"), // enum,
+ @OpenApiContent(from = CustomNameEntity.class, mimeType = "app/custom-name-entity") // custom name
+ }
),
- @OpenApiResponse(status = "401", description = "Error message related to the unauthorized access", content = {
- @OpenApiContent(from = EntityDto[].class)
- })
- }
+ responses = {
+ @OpenApiResponse(status = "200", description = "Status of the executed command", content = {
+ @OpenApiContent(from = String.class, example = "Value"),
+ @OpenApiContent(from = EntityDto[].class)
+ }),
+ @OpenApiResponse(
+ status = "400",
+ description = "Error message related to the invalid command format (0 < command length < " + 10 + ")",
+ content = @OpenApiContent(from = EntityDto[].class),
+ headers = {
+ @OpenApiParam(name = "X-Error-Message", description = "Error message")
+ }
+ ),
+ @OpenApiResponse(status = "401", description = "Error message related to the unauthorized access", content = {
+ @OpenApiContent(from = EntityDto[].class, exampleObjects = {
+ @OpenApiExampleProperty(name = "error", value = "ERROR-CODE-401"),
+ })
+ }),
+ @OpenApiResponse(status = "500") // fill description with HttpStatus message
+ },
+ callbacks = {
+ @OpenApiCallback(
+ name = "onData",
+ url = "{$request.query.callbackUrl}/data",
+ method = HttpMethod.GET,
+ requestBody = @OpenApiRequestBody(
+ description = "Callback request body",
+ content = @OpenApiContent(from = String.class)
+ ),
+ responses = {
+ @OpenApiResponse(
+ status = "200",
+ description = "Callback response",
+ content = { @OpenApiContent(from = String.class) }
+ )
+ }
+ ),
+ }
+ )
+ @OpenApi(
+ path = "/repeatable",
+ methods = { HttpMethod.POST },
+ versions = "v1",
+ requestBody = @OpenApiRequestBody(
+ description = "Complex bodies",
+ content = {
+ @OpenApiContent(from = EntityDto[].class), // array
+ @OpenApiContent(from = File.class), // file
+ @OpenApiContent(type = "application/json"), // empty
+ @OpenApiContent(), // empty
+ @OpenApiContent(mimeType = "image/png", type = "string", format = "base64"), // single file upload,
+ @OpenApiContent(mimeType = "multipart/form-data", properties = {
+ @OpenApiContentProperty(name = "form-element", type = "integer"), // random element in form-data
+ @OpenApiContentProperty(name = "reference", from = KotlinEntity.class), // reference to another object
+ @OpenApiContentProperty(name = "file-name", isArray = true, type = "string", format = "base64") // multi-file upload
+ })
+ }
+ )
)
- public void handle(@NotNull Context ctx) { }
+ @Override
+ public void handle(@NotNull Context ctx) {}
+ @OpenApi(
+ path = "/standalone",
+ methods = HttpMethod.DELETE,
+ versions = "v2",
+ headers = { @OpenApiParam(name = "V2") }
+ )
+ @OpenApi(
+ path = "standalone",
+ methods = HttpMethod.DELETE,
+ versions = "v1",
+ headers = { @OpenApiParam(name = "V1") }
+ )
static final class EntityDto implements Serializable {
private final int status;
@@ -212,7 +244,12 @@ static final class EntityDto implements Serializable {
private final @NotNull String timestamp;
private final @NotNull Foo foo;
private final @NotNull List foos;
-
+ private final @NotNull Map> bars = new HashMap<>();
+ private final @NotNull EnumEntity enumEntity = EnumEntity.TWO;
+ // should be displayed as standard json section
+ // should be ignored
+ @Getter
+ @Setter
private Bar bar;
public EntityDto(int status, @NotNull String message, @NotNull Foo foo, @NotNull List foos, @Nullable Bar bar) {
@@ -224,14 +261,9 @@ public EntityDto(int status, @NotNull String message, @NotNull Foo foo, @NotNull
this.timestamp = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT);
}
- // should ignore
- public void setBar(Bar bar) {
- this.bar = bar;
- }
-
- // should be displayed as standard json section
- public Bar getBar() {
- return bar;
+ // should be represented as object
+ public @NotNull Map> getBars() {
+ return bars;
}
// should be represented by array
@@ -239,12 +271,28 @@ public Bar getBar() {
return foos;
}
+ // should handle fallback to object type
+ @SuppressWarnings("rawtypes")
+ public List getUnknowns() {
+ return foos;
+ }
+
+ // should display enum
+ public @NotNull EnumEntity getEnumEntity() {
+ return enumEntity;
+ }
+
// should be displayed as string
@OpenApiPropertyType(definedBy = String.class)
public @NotNull Foo getFoo() {
return foo;
}
+ // HiddenEntity with @OpenApiPropertyType should be displayed as string
+ public HiddenEntity getHiddenEntity() {
+ return new HiddenEntity();
+ }
+
// should support primitive types
public int getStatus() {
return status;
@@ -256,7 +304,7 @@ public String getMessageValue() {
return message;
}
- // should ignore
+ // should be ignored
@OpenApiIgnore
public String getFormattedMessage() {
return status + message;
@@ -268,43 +316,247 @@ public String getFormattedMessage() {
return timestamp;
}
+ // should contain examples
+ @OpenApiExample(objects = {
+ @OpenApiExampleProperty(value = "2022-08-14T21:13:03.546Z"),
+ @OpenApiExampleProperty(value = "2022-08-14T21:13:03.546Z")
+ })
+ public @NotNull String[] getTimestamps() {
+ return new String[] { timestamp };
+ }
+
+ // should contain dedicated foo example
+ @OpenApiExample(objects = {
+ @OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
+ @OpenApiExampleProperty(name = "link", value = "Dedicated link")
+ })
+ public @NotNull Foo getExampleFoo() {
+ return new Foo();
+ }
+
+ // should contain object example
+ @OpenApiExample(objects = {
+ @OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
+ @OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ })
+ public @NotNull Object getExampleObject() {
+ return new String[] { timestamp };
+ }
+
+ // should contain objects example
+ @OpenApiExample(objects = {
+ @OpenApiExampleProperty(name = "Barbie", objects = {
+ @OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
+ @OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ }),
+ })
+ public @NotNull Object[] getExampleObjects() {
+ return new String[] { timestamp };
+ }
+
// should contain example for primitive types, SwaggerUI will automatically display this as an Integer
@OpenApiExample("5050")
+ @OpenApiNumberValidation(
+ minimum = "5000",
+ exclusiveMinimum = true,
+ maximum = "6000",
+ exclusiveMaximum = true,
+ multipleOf = "50"
+ )
+ @OpenApiStringValidation(
+ minLength = "4",
+ maxLength = "4",
+ pattern = "^[0-9]{4}$",
+ format = "int32"
+ )
+ @OpenApiArrayValidation(
+ minItems = "1",
+ maxItems = "1",
+ uniqueItems = true
+ )
+ @OpenApiObjectValidation(
+ minProperties = "1",
+ maxProperties = "1"
+ )
public int getVeryImportantNumber() {
return status + 1;
}
- }
+ @OpenApiDescription("Some description")
+ public String getDescription() {
+ return "Description";
+ }
- static final class Foo {
+ // should support @Custom from JsonSchema
+ @Custom(name = "description", value = "Custom property")
+ public String getCustom() {
+ return "";
+ }
- private String property;
- private String link;
+ // should be displayed as string
+ public ObjectId getObjectId() {
+ return new ObjectId();
+ }
- public String getProperty() {
- return property;
+ // static should be ignored
+ public static String getStatic() {
+ return "static";
}
+ // by default nullable fields are not required, but we can force it
+ //@OpenApiRequired
+ public JsonSchemaEntity getNullableIsRequired() {
+ return null;
+ }
+
+ }
+
+ static final class Foo {
+
@OpenApiExample("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
public String getLink() {
- return link;
+ return "";
}
-
}
+ // subtype
+ @Getter
static final class Bar {
+ private String property;
+ }
+
+ // should work with properties generated by another annotation processor
+ @Data
+ static final class LombokEntity {
private String property;
+ }
+
+ // should pick upper/lower bound type for generics
+ @Getter
+ static final class EntityWithGenericType {
- public String getProperty() {
- return property;
+ private final V value;
+
+ public EntityWithGenericType(V value) {
+ this.value = value;
}
}
- @Data
- static final class LombokEntity {
- private String property;
+ // should query fields
+ @OpenApiByFields(value = Visibility.PROTECTED, only = true) // by default: PUBLIC
+ static final class DtoWithFields {
+
+ public String publicName;
+ String defaultName;
+ protected String protectedName;
+ private String privateName;
+
+ public String getCustom() {
+ return "custom";
+ }
+ }
+
+ // should query fields and methods
+ @OpenApiByFields(Visibility.PROTECTED) // by default: PUBLIC
+ static final class DtoWithFieldsAndMethods {
+
+ public String publicName;
+ String defaultName;
+ protected String protectedName;
+ private String privateName;
+
+ public String getCustom() {
+ return "custom";
+ }
+ }
+
+ enum EnumEntity {
+
+ ONE("A"),
+ TWO("B");
+
+ private final String name;
+
+ EnumEntity(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ Enum> e = EnumEntity.TWO;
+ return name;
+ }
+
+ }
+
+ @JsonSchema(requireNonNulls = false)
+ static final class JsonSchemaEntity {
+
+ @OpenApiRequired
+ public List getEntities() {
+ return Collections.emptyList();
+ }
+
+ @OneOf({ Panda.class, Cat.class })
+ public Animal getAnimal() {
+ return new Panda();
+ }
+
+ }
+
+ interface Animal {
+
+ default boolean isAnimal() {
+ return true;
+ }
+
}
+ static class Panda implements Animal {
+
+ @Custom(name = "title", value = "Panda")
+ @Custom(name = "description", value = "Only Panda")
+ public boolean isPanda() {
+ return true;
+ }
+
+ }
+
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @CustomAnnotation
+ @interface Description {
+
+ String title();
+
+ String description();
+
+ int statusCode();
+ }
+
+ static class Cat implements Animal {
+
+ @Description(title = "Cat", description = "Is it cat?", statusCode = 200)
+ public boolean isCat() {
+ return true;
+ }
+
+ }
+
+ @OpenApiPropertyType(definedBy = String.class)
+ static class HiddenEntity {
+
+ }
+
+ @OpenApiName("EntityWithCustomName")
+ static class CustomNameEntity {}
+
+ @Data
+ @AllArgsConstructor
+ public static class RecordEntity {
+ @NotEmpty
+ private String name;
+ @NotEmpty
+ private String surname;
+ }
}