Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ To force the AP to generate with `@javax.inject.Singleton`(in the case where you
</plugin>
```

OpenAPI output is generated as OpenAPI 3.1.

The generated document sets:

- `openapi: 3.1.2`

### Usage with Javalin

The annotation processor will generate controller classes implementing the `AvajeJavalinPlugin` interface, which we can register in javalin using:
Expand Down
4 changes: 4 additions & 0 deletions http-generator-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
<pattern>io.avaje.http.generator.core</pattern>
<shadedPattern>io.avaje.http.client.generator.core</shadedPattern>
</relocation>
<relocation>
<pattern>io.avaje.http.openapi</pattern>
<shadedPattern>io.avaje.http.client.generator.openapi</shadedPattern>
</relocation>
<relocation>
<pattern>io.swagger.v3</pattern>
<shadedPattern>io.avaje.http.client.generator.swagger.v3</shadedPattern>
Expand Down
6 changes: 6 additions & 0 deletions http-generator-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-http-openapi-core</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.SpecVersion;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.Schema;
Expand Down Expand Up @@ -65,6 +66,9 @@ public boolean isOpenApiAvailable() {

private OpenAPI initOpenAPI() {
OpenAPI openAPI = new OpenAPI();
openAPI.setOpenapi("3.1.2");
openAPI.setSpecVersion(SpecVersion.V31);
openAPI.setJsonSchemaDialect("https://spec.openapis.org/oas/3.1/dialect/base");
openAPI.setPaths(new Paths());

Server server = new Server();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public Schema<?> createSchema() {
private class BoolType implements KnownType {
@Override
public Schema<?> createSchema() {
return new BooleanSchema().nullable(Boolean.FALSE);
return new BooleanSchema();
}
}

Expand All @@ -115,14 +115,14 @@ public Schema<?> createSchema() {
private class IntType implements KnownType {
@Override
public Schema<?> createSchema() {
return new IntegerSchema().nullable(Boolean.FALSE);
return new IntegerSchema();
}
}

private class IntArrayType implements KnownType {
@Override
public Schema<?> createSchema() {
return new ArraySchema().items(new IntegerSchema().nullable(Boolean.FALSE));
return new ArraySchema().items(new IntegerSchema());
}
}

Expand All @@ -136,14 +136,14 @@ public Schema<?> createSchema() {
private class PLongType implements KnownType {
@Override
public Schema<?> createSchema() {
return new IntegerSchema().format("int64").nullable(Boolean.FALSE);
return new IntegerSchema().format("int64");
}
}

private class PLongArrayType implements KnownType {
@Override
public Schema<?> createSchema() {
return new ArraySchema().items(new IntegerSchema().format("int64").nullable(Boolean.FALSE));
return new ArraySchema().items(new IntegerSchema().format("int64"));
}
}

Expand All @@ -157,14 +157,14 @@ public Schema<?> createSchema() {
private class PNumberType implements KnownType {
@Override
public Schema<?> createSchema() {
return new NumberSchema().nullable(Boolean.FALSE);
return new NumberSchema();
}
}

private class PNumberArrayType implements KnownType {
@Override
public Schema<?> createSchema() {
return new ArraySchema().items(new NumberSchema().nullable(Boolean.FALSE));
return new ArraySchema().items(new NumberSchema());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package io.avaje.http.generator.core.openapi;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import io.avaje.http.openapi.OpenApiSchemaNormalizer;
import io.swagger.v3.oas.models.media.Schema;

final class OpenAPISerializer {

private static final Set<String> IGNORED_FIELDS = Set.of(
Expand All @@ -17,7 +21,7 @@ final class OpenAPISerializer {
"USE_ARBITRARY_SCHEMA_PROPERTY",
"exampleSetFlag",
"defaultSetFlag",
"types",
"nullable",
"specVersion");

private OpenAPISerializer() {}
Expand Down Expand Up @@ -77,6 +81,9 @@ static String serialize(Object obj) throws IllegalAccessException {

var firstField = true;
for (final Field field : fields) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}

// skip JsonIgnored fields
if (IGNORED_FIELDS
Expand All @@ -85,14 +92,31 @@ static String serialize(Object obj) throws IllegalAccessException {
}

field.setAccessible(true);
final var value = field.get(obj);
Object value = field.get(obj);
if (obj instanceof Schema<?>) {
final Schema<?> schema = (Schema<?>) obj;
if ("type".equals(field.getName()) && OpenApiSchemaNormalizer.hasTypeSet(schema)) {
continue;
}
if (skipSchemaField(schema, field.getName())) {
continue;
}
if ("types".equals(field.getName())) {
value = OpenApiSchemaNormalizer.schemaTypeValue(schema);
} else if ("exclusiveMaximumValue".equals(field.getName())) {
value = OpenApiSchemaNormalizer.exclusiveMaximumValue(schema);
} else if ("exclusiveMinimumValue".equals(field.getName())) {
value = OpenApiSchemaNormalizer.exclusiveMinimumValue(schema);
}
}
if (value != null) {

if (!firstField) {
sb.append(",");
}
final var jsonFieldName = jsonFieldName(obj, field.getName());
sb.append("\"");
sb.append(field.getName().replace("_enum", "enum"));
sb.append(jsonFieldName);
sb.append("\" : ");
write(sb, value);
firstField = false;
Expand Down Expand Up @@ -128,6 +152,32 @@ static Field[] getAllFields(Class<?> clazz) {
}
}

private static boolean skipSchemaField(Schema<?> schema, String fieldName) {
if ("exclusiveMaximum".equals(fieldName) || "exclusiveMinimum".equals(fieldName)) {
return true;
}
if ("maximum".equals(fieldName) && OpenApiSchemaNormalizer.omitMaximum(schema)) {
return true;
}
return "minimum".equals(fieldName) && OpenApiSchemaNormalizer.omitMinimum(schema);
}

private static String jsonFieldName(Object container, String fieldName) {
if ("_enum".equals(fieldName)) {
return "enum";
}
if (container instanceof Schema<?> && "types".equals(fieldName)) {
return "type";
}
if (container instanceof Schema<?> && "exclusiveMaximumValue".equals(fieldName)) {
return "exclusiveMaximum";
}
if (container instanceof Schema<?> && "exclusiveMinimumValue".equals(fieldName)) {
return "exclusiveMinimum";
}
return fieldName;
}

static boolean isPrimitiveWrapperType(Object value) {

return value instanceof Boolean
Expand Down Expand Up @@ -178,7 +228,9 @@ static Object extractPrimitiveValue(Object object) {
static void write(StringBuilder sb, Object value) throws IllegalAccessException {
final var isPrimitiveWrapper = isPrimitiveWrapperType(value);
// Append primitive or string value as is
if (value.getClass().isPrimitive() || value instanceof String || isPrimitiveWrapper) {
if (value instanceof Number) {
sb.append(value);
} else if (value.getClass().isPrimitive() || value instanceof String || isPrimitiveWrapper) {
if (isPrimitiveWrapper) {
sb.append(extractPrimitiveValue(value));
} else {
Expand Down
Loading