Skip to content

Commit

Permalink
#484 feat: initial implementation of microprofile-openapi-3
Browse files Browse the repository at this point in the history
  • Loading branch information
dcdh committed Oct 12, 2024
1 parent 7a5cb07 commit 7db5831
Show file tree
Hide file tree
Showing 22 changed files with 1,300 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- support `<skipAbstractTypes>` flag to exclude abstract types (not interfaces)
- support `<skipInterfaces>` flag to exclude interface types

### `jsonschema-module-microprofile-openapi-3`
#### Added
***NOTE: `org.eclipse.microprofile.openapi:microprofile-openapi-api` minimum version is `3.1.1`!***
- Initial implementation of `MicroProfileOpenApi3Module` for deriving schema attributes from MicroProfile OpenAPI 3 `@Schema` annotations.

## [4.36.0] - 2024-07-20
### `jsonschema-generator`
#### Added
Expand Down
9 changes: 9 additions & 0 deletions jsonschema-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!-- Microprofile OpenAPI 3 Module dependencies -->
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-module-microprofile-openapi-3</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions jsonschema-generator-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
<artifactId>jsonschema-module-swagger-2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-module-microprofile-openapi-3</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
6 changes: 6 additions & 0 deletions jsonschema-generator-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
<version.javax.validation>2.0.1.Final</version.javax.validation>
<version.swagger-1.5>1.6.7</version.swagger-1.5>
<version.swagger-2>2.2.5</version.swagger-2>
<version.microprofile-openapi-3>3.1.1</version.microprofile-openapi-3>
<!-- maven plugin runtime dependencies -->
<version.classgraph>4.8.149</version.classgraph>
</properties>
Expand Down Expand Up @@ -212,6 +213,11 @@
<artifactId>classgraph</artifactId>
<version>${version.classgraph}</version>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<version>${version.microprofile-openapi-3}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
Expand Down
3 changes: 2 additions & 1 deletion jsonschema-maven-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,13 @@ When you want to have more control over the modules that are to be used during g
```
This configuration will generate the schema using the Jackson module.

There are five standard modules that can be used:
There are six standard modules that can be used:
- `Jackson`
- `JakartaValidation`
- `JavaxValidation`
- `Swagger15`
- `Swagger2`
- `MicroProfileOpenApi3`

### Defining options for a module
```xml
Expand Down
9 changes: 9 additions & 0 deletions jsonschema-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!-- Microprofile OpenAPI 3 Module dependencies -->
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-module-microprofile-openapi-3</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption;
import com.github.victools.jsonschema.module.javax.validation.JavaxValidationModule;
import com.github.victools.jsonschema.module.javax.validation.JavaxValidationOption;
import com.github.victools.jsonschema.module.microprofile.openapi3.MicroProfileOpenApi3Module;
import com.github.victools.jsonschema.module.swagger15.SwaggerModule;
import com.github.victools.jsonschema.module.swagger15.SwaggerOption;
import com.github.victools.jsonschema.module.swagger2.Swagger2Module;
Expand Down Expand Up @@ -522,9 +523,14 @@ private void addStandardModule(GeneratorModule module, SchemaGeneratorConfigBuil
this.getLog().debug("- Adding Swagger 2.x Module");
configBuilder.with(new Swagger2Module());
break;
case "MicroProfileOpenApi3":
this.getLog().debug("- Adding MicroProfile OpenAPI 3.x Module");
configBuilder.with(new MicroProfileOpenApi3Module());
break;
default:
throw new MojoExecutionException("Error: Module does not have a name in "
+ "['Jackson', 'JakartaValidation', 'JavaxValidation', 'Swagger15', 'Swagger2'] or does not have a custom classname.");
+ "['Jackson', 'JakartaValidation', 'JavaxValidation', 'Swagger15', 'Swagger2', 'MicroProfileOpenApi3']"
+ " or does not have a custom classname.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public void setUp() throws Exception {
"JakartaValidationModule",
"Swagger15Module",
"Swagger2Module",
"MicroProfileOpenApi3Module",
"Complete"
})
public void testGeneration(String testCaseName) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<project>
<build>
<plugins>
<plugin>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-maven-plugin</artifactId>
<configuration>
<classNames>com.github.victools.jsonschema.plugin.maven.TestClass</classNames>
<schemaFilePath>target/generated-test-sources/MicroProfileOpenApi3Module</schemaFilePath>
<modules>
<module>
<name>MicroProfileOpenApi3</name>
</module>
</modules>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema" : "http://json-schema.org/draft-07/schema#",
"type" : "object",
"properties" : {
"anInt" : {
"type" : "integer"
}
}
}
94 changes: 94 additions & 0 deletions jsonschema-module-microprofile-openapi-3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Java JSON Schema Generator – Module Microprofile OpenAPI (3.x)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.victools/jsonschema-module-microprofile-openapi-3/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.victools/jsonschema-module-microprofile-openapi-3)
Module for the [jsonschema-generator](../jsonschema-generator) – deriving JSON Schema attributes from `microprofile-openapi-api` (3.x) annotations

## Features
1. From `@Schema(description = …)` on types in general, derive `"description"`.
2. From `@Schema(title = …)` on types in general, derive `"title"`.
3. From `@Schema(ref = …)` on types in general, replace subschema with `"$ref"` to external/separate schema (except for the main type being targeted).
4. From `@Schema(subTypes = …)` on types in general, derive `"anyOf"` alternatives.
5. From `@Schema(anyOf = …)` on types in general (as alternative to `subTypes`), derive `"anyOf"` alternatives.
6. From `@Schema(name = …)` on types in general, derive the keys/names in `"definitions"`/`"$defs"`.
7. From `@Schema(description = …)` on fields/methods, derive `"description"`.
8. From `@Schema(title = …)` on fields/methods, derive `"title"`.
9. From `@Schema(implementation = …)` on fields/methods, override represented type.
10. From `@Schema(hidden = true)` on fields/methods, skip certain properties.
11. From `@Schema(name = …)` on fields/methods, override property names.
12. From `@Schema(ref = …)` on fields/methods, replace subschema with `"$ref"` to external/separate schema.
13. From `@Schema(allOf = …)` on fields/methods, include `"allOf"` parts.
14. From `@Schema(anyOf = …)` on fields/methods, include `"anyOf"` parts.
15. From `@Schema(oneOf = …)` on fields/methods, include `"oneOf"` parts.
16. From `@Schema(not = …)` on fields/methods, include the indicated `"not"` subschema.
17. From `@Schema(required = true)` on fields/methods, mark property as `"required"` in the schema containing the property.
18. From `@Schema(requiredProperties = …)` on fields/methods, derive its `"required"` properties.
19. From `@Schema(minProperties = …)` on fields/methods, derive its `"minProperties"`.
20. From `@Schema(maxProperties = …)` on fields/methods, derive its `"maxProperties"`.
21. From `@Schema(nullable = true)` on fields/methods, include `null` in its `"type"` - when schema type is ARRAY, applied on array item only.
22. From `@Schema(allowableValues = …)` on fields/methods, derive its `"const"`/`"enum"`.
23. From `@Schema(defaultValue = …)` on fields/methods, derive its `"default"` - when schema type is ARRAY, applied on array item only.
24. From `@Schema(readOnly = …)` on fields/methods, to mark them as `"readOnly"`.
25. From `@Schema(writeOnly = …)` on fields/methods, to mark them as `"writeOnly"`.
26. From `@Schema(minLength = …)` on fields/methods, derive its `"minLength"`.
27. From `@Schema(maxLength = …)` on fields/methods, derive its `"maxLength"`.
28. From `@Schema(format = …)` on fields/methods, derive its `"format"`.
29. From `@Schema(pattern = …)` on fields/methods, derive its `"pattern"`.
30. From `@Schema(multipleOf = …)` on fields/methods, derive its `"multipleOf"`.
31. From `@Schema(minimum = …, exclusiveMinimum = …)` on fields/methods, derive its `"minimum"`/`"exclusiveMinimum"`.
32. From `@Schema(maximum = …, exclusiveMaximum = …)` on fields/methods, derive its `"maximum"`/`"exclusiveMaximum"`.
33. From `@Schema(minItems = …)` on fields/methods when schema type is ARRAY, derive its `"minItems"`.
34. From `@Schema(maxItems = …)` on fields/methods when schema type is ARRAY, derive its `"maxItems"`.
35. From `@Schema(uniqueItems = …)` on fields/methods when schema type is ARRAY, derive its `"uniqueItems"`.

Schema attributes derived from `@Schema` on fields are also applied to their respective getter methods.
Schema attributes derived from `@Schema` on getter methods are also applied to their associated fields.

----

## Documentation
JavaDoc is being used throughout the codebase, offering contextual information in your respective IDE or being available online through services like [javadoc.io](https://www.javadoc.io/doc/com.github.victools/jsonschema-module-microprofile-openapi-3).

Additional documentation can be found in the [Project Wiki](https://github.com/victools/jsonschema-generator/wiki).

----

## Usage
### Dependency (Maven)
```xml
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-module-microprofile-openapi-3</artifactId>
<version>[4.37.0,)</version>
</dependency>
```

The release versions of the main generator library and this module are aligned.
It is recommended to use identical versions for both dependencies to ensure compatibility.

### Code
#### Passing into SchemaGeneratorConfigBuilder.with(Module)

```java


```
```java
MicroProfileOpenApi3Module module = new MicroProfileOpenApi3Module();
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09)
.with(module);
```

#### Complete Example

```java

```
```java
MicroProfileOpenApi3Module module = new MicroProfileOpenApi3Module();
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON)
.with(module);
SchemaGeneratorConfig config = configBuilder.build();
SchemaGenerator generator = new SchemaGenerator(config);
JsonNode jsonSchema = generator.generateSchema(YourClass.class);

System.out.println(jsonSchema.toString());
```
54 changes: 54 additions & 0 deletions jsonschema-module-microprofile-openapi-3/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-generator-parent</artifactId>
<version>4.37.0-SNAPSHOT</version>
<relativePath>../jsonschema-generator-parent/pom.xml</relativePath>
</parent>
<artifactId>jsonschema-module-microprofile-openapi-3</artifactId>

<name>Java JSON Schema Generator Module – Microprofile OpenAPI (3.x)</name>
<description>Module for the jsonschema-generator – Microprofile OpenAPI (3.x)</description>

<properties>
<java.module.name>com.github.victools.jsonschema.module.microprofile.openapi3</java.module.name>
</properties>

<dependencies>
<dependency>
<groupId>com.github.victools</groupId>
<artifactId>jsonschema-generator</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2024 VicTools.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.victools.jsonschema.module.microprofile.openapi3;

import com.fasterxml.classmate.ResolvedType;
import com.github.victools.jsonschema.generator.CustomDefinition;
import com.github.victools.jsonschema.generator.CustomDefinitionProviderV2;
import com.github.victools.jsonschema.generator.SchemaGenerationContext;
import com.github.victools.jsonschema.generator.SchemaKeyword;
import java.util.Optional;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

/**
* Replace any type annotated with {@code @Schema(ref = "...")} with the specified reference value, unless it is the main schema being targeted.
*/
public class ExternalRefCustomDefinitionProvider implements CustomDefinitionProviderV2 {

/**
* Reference to the targeted type, for which a schema is being generated, that should not be replaced by a "ref".
*/
private Class<?> mainType;

@Override
public CustomDefinition provideCustomSchemaDefinition(ResolvedType javaType, SchemaGenerationContext context) {
Class<?> erasedType = javaType.getErasedType();
if (this.mainType == null) {
this.mainType = erasedType;
}
if (this.mainType == erasedType) {
return null;
}
return Optional.ofNullable(erasedType.getAnnotation(Schema.class))
.map(Schema::ref)
.filter(ref -> !ref.isEmpty())
.map(ref -> context.getGeneratorConfig().createObjectNode().put(context.getKeyword(SchemaKeyword.TAG_REF), ref))
.map(schema -> new CustomDefinition(schema, CustomDefinition.INLINE_DEFINITION, CustomDefinition.INCLUDING_ATTRIBUTES))
.orElse(null);
}

@Override
public void resetAfterSchemaGenerationFinished() {
this.mainType = null;
}
}
Loading

0 comments on commit 7db5831

Please sign in to comment.