Skip to content

Commit

Permalink
Support OpenAPI x-class-extra-annotation property (#209)
Browse files Browse the repository at this point in the history
Adds support for the OpenAPI property `x-class-extra-annotation` (vendor-extension). The property can be set either as a string (for one annotation), or as a literal block `|-` (for multiple annotations). The property is only applicable for `record` classes. The property _could_ conflict with `additionalModelTypeAnnotations` when referring to the same annotation (_if the annotation is not **repeatable**_).
  • Loading branch information
Chrimle authored Dec 3, 2024
1 parent 060c841 commit 90979fc
Show file tree
Hide file tree
Showing 115 changed files with 1,044 additions and 101 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The mustache templates can be acquired through multiple ways.
<dependency>
<groupId>io.github.chrimle</groupId>
<artifactId>openapi-to-java-records-mustache-templates</artifactId>
<version>2.2.1</version>
<version>2.3.0</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The mustache templates can be acquired through multiple ways.
<dependency>
<groupId>io.github.chrimle</groupId>
<artifactId>openapi-to-java-records-mustache-templates</artifactId>
<version>2.2.1</version>
<version>2.3.0</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>io.github.chrimle</groupId>
<artifactId>openapi-to-java-records-mustache-templates</artifactId>
<version>2.2.1</version>
<version>2.3.0</version>

<!-- Project Information -->
<name>OpenAPI to Java records :: Mustache Templates</name>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.chrimle.example.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestExtraAnnotation {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.chrimle.example.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestExtraAnnotationTwo {}
18 changes: 18 additions & 0 deletions src/main/resources/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,24 @@ components:
field1:
type: boolean
description: a boolean field
ExampleRecordWithOneExtraAnnotation:
type: object
description: Example of a Record with an extra annotation
x-class-extra-annotation: '@io.github.chrimle.example.annotations.TestExtraAnnotation'
properties:
field1:
type: boolean
description: a boolean field
ExampleRecordWithTwoExtraAnnotations:
type: object
description: Example of a Record with two extra annotations
x-class-extra-annotation: |-
@io.github.chrimle.example.annotations.TestExtraAnnotation
@io.github.chrimle.example.annotations.TestExtraAnnotationTwo
properties:
field1:
type: boolean
description: a boolean field
ExampleRecordWithDefaultFields:
type: object
description: Example of a Record with default fields
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/generateBuilders.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is a custom template, and is used by `pojo.mustache`.
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/javadoc.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is a custom template, and is used by `pojo.mustache` and `modelEnum.mustache`.
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/templates/licenseInfo.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is overriding an official 'openapi-generator-maven-plugin' template.
Expand All @@ -33,6 +33,6 @@
* openapi-to-java-records-mustache-templates. For further information,
* questions, requesting features or reporting issues, please visit:
* https://github.com/Chrimle/openapi-to-java-records-mustache-templates.
* Generated with Version: 2.2.1
* Generated with Version: 2.3.0
*
*/
2 changes: 1 addition & 1 deletion src/main/resources/templates/modelEnum.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is overriding an official 'openapi-generator-maven-plugin' template.
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/templates/pojo.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is overriding an official 'openapi-generator-maven-plugin' template.
Expand All @@ -30,6 +30,9 @@
}}{{#isDeprecated}}@Deprecated
{{/isDeprecated}}{{!
}}{{>additionalModelTypeAnnotations}}{{!
}}{{#vendorExtensions.x-class-extra-annotation}}{{!
}}{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}{{!
}}public record {{classname}}(
{{#vars}}@{{javaxPackage}}.annotation.{{#isNullable}}Nullable{{/isNullable}}{{^isNullable}}Nonnull{{/isNullable}}{{>useBeanValidation}} {{{datatypeWithEnum}}} {{name}}{{^-last}},
{{/-last}}{{/vars}}{{^serializableModel}}){{/serializableModel}}{{#serializableModel}}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/serializableModel.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is a custom template, and is used by `pojo.mustache`.
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/useBeanValidation.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}}{{!
Source: openapi-to-java-records-mustache-templates
Version: 2.2.1
Version: 2.3.0
This template is a custom template, and is used by `pojo.mustache`.
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/io/github/chrimle/example/GeneratedSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import io.github.chrimle.example.models.GeneratedClass;
import io.github.chrimle.example.models.GeneratedField;
import io.github.chrimle.example.utils.AssertionUtils;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;

/**
* Represents a generated <i>source</i>, which contains:
Expand Down Expand Up @@ -93,6 +95,14 @@ public boolean isDeprecated() {
return generatedClass.isDeprecated();
}

public boolean hasExtraAnnotations() {
return generatedClass.hasExtraAnnotations();
}

public List<Class<? extends Annotation>> getExtraAnnotations() {
return generatedClass.getExtraAnnotations();
}

public Class<?>[] fieldClasses() {
return Arrays.stream(generatedFields).map(GeneratedField::type).toArray(Class<?>[]::new);
}
Expand Down
28 changes: 25 additions & 3 deletions src/test/java/io/github/chrimle/example/models/GeneratedClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package io.github.chrimle.example.models;

import io.github.chrimle.example.PluginExecution;
import java.lang.annotation.Annotation;
import java.util.List;

/**
* Enum class listing all expected classes ({@code record}s and {@code enum}s) to be generated from
Expand All @@ -35,8 +37,8 @@ public interface GeneratedClass {
String getSimpleClassName();

/**
* Whether the class is marked as deprecated. If {@code true}, the class should be annotated with
* {@link Deprecated}.
* Whether the class is marked as deprecated, set by the property {@code deprecated}. If {@code
* true}, the class should be annotated with {@link Deprecated}.
*
* @return whether the class is deprecated.
*/
Expand All @@ -50,9 +52,29 @@ public interface GeneratedClass {
*/
boolean isEnum();

/**
* Whether the class has extra {@link Annotation}s, set by the {@code x-class-extra-annotation}
* property.
*
* <p><b>NOTE:</b> this property does not support {@code enum} classes.
*
* @return whether the class has extra annotations.
*/
boolean hasExtraAnnotations();

/**
* Returns the collection of extra {@link Annotation}s, set by the {@code
* x-class-extra-annotation} property.
*
* <p><b>NOTE:</b> this property does not support {@code enum} classes.
*
* @return the collection of annotations.
*/
List<Class<? extends Annotation>> getExtraAnnotations();

/**
* Returns the collection of {@link GeneratedField}s which are expected to be generated within the
* class.
* class. Corresponds to each {@code properties}-item.
*
* @return the collection of generatedFields.
*/
Expand Down
23 changes: 23 additions & 0 deletions src/test/java/io/github/chrimle/example/models/GeneratedEnum.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
package io.github.chrimle.example.models;

import java.lang.annotation.Annotation;
import java.util.List;

/** Enum class listing all expected {@code enum} classes to be generated from the OpenAPI spec. */
public enum GeneratedEnum implements GeneratedClass {
DEPRECATED_EXAMPLE_ENUM(
Expand Down Expand Up @@ -94,6 +97,26 @@ public boolean isEnum() {
return true;
}

/**
* {@inheritDoc}
*
* @return whether the class has extra annotations.
*/
@Override
public boolean hasExtraAnnotations() {
return false;
}

/**
* {@inheritDoc}
*
* @return the collection of annotations.
*/
@Override
public List<Class<? extends Annotation>> getExtraAnnotations() {
return List.of();
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
package io.github.chrimle.example.models;

import io.github.chrimle.example.annotations.TestExtraAnnotation;
import io.github.chrimle.example.annotations.TestExtraAnnotationTwo;
import java.lang.annotation.Annotation;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
Expand All @@ -24,15 +27,31 @@
/** Enum class listing all expected {@code record} classes to be generated from the OpenAPI spec. */
public enum GeneratedRecord implements GeneratedClass {
DEPRECATED_EXAMPLE_RECORD(
"DeprecatedExampleRecord", true, GeneratedField.of("field1", Boolean.class).build()),
EXAMPLE_RECORD("ExampleRecord", false, GeneratedField.of("field1", Boolean.class).build()),
"DeprecatedExampleRecord",
true,
List.of(),
GeneratedField.of("field1", Boolean.class).build()),
EXAMPLE_RECORD(
"ExampleRecord", false, List.of(), GeneratedField.of("field1", Boolean.class).build()),
EXAMPLE_RECORD_WITH_DEFAULT_FIELDS(
"ExampleRecordWithDefaultFields",
false,
List.of(),
GeneratedField.of("field1", String.class).defaultValue("someDefaultValue").build()),
EXAMPLE_RECORD_WITH_ONE_EXTRA_ANNOTATION(
"ExampleRecordWithOneExtraAnnotation",
false,
List.of(TestExtraAnnotation.class),
GeneratedField.of("field1", Boolean.class).build()),
EXAMPLE_RECORD_WITH_TWO_EXTRA_ANNOTATIONS(
"ExampleRecordWithTwoExtraAnnotations",
false,
List.of(TestExtraAnnotation.class, TestExtraAnnotationTwo.class),
GeneratedField.of("field1", Boolean.class).build()),
EXAMPLE_RECORD_WITH_NULLABLE_FIELDS_OF_EACH_TYPE(
"ExampleRecordWithNullableFieldsOfEachType",
false,
List.of(),
GeneratedField.of("field1", Boolean.class).isNullable(true).build(),
GeneratedField.of("field2", String.class).isNullable(true).build(),
GeneratedField.of("field3", Integer.class).isNullable(true).build(),
Expand All @@ -45,10 +64,11 @@ public enum GeneratedRecord implements GeneratedClass {
* io.github.chrimle.example.TestSuite}.
*/
EXAMPLE_RECORD_WITH_REQUIRED_FIELDS_OF_EACH_TYPE(
"ExampleRecordWithRequiredFieldsOfEachType", false),
"ExampleRecordWithRequiredFieldsOfEachType", false, List.of()),
RECORD_WITH_ALL_CONSTRAINTS(
"RecordWithAllConstraints",
false,
List.of(),
GeneratedField.of("stringStandard", String.class).build(),
GeneratedField.of("stringDefault", String.class).defaultValue("someDefaultValue").build(),
GeneratedField.of("stringNullable", String.class).isNullable(true).build(),
Expand Down Expand Up @@ -83,18 +103,23 @@ public enum GeneratedRecord implements GeneratedClass {
* does not list all expected fields to be generated. This is done in {@link
* io.github.chrimle.example.TestSuite}.
*/
RECORD_WITH_INNER_ENUMS("RecordWithInnerEnums", false);
RECORD_WITH_INNER_ENUMS("RecordWithInnerEnums", false, List.of());

private final String simpleClassName;
private final boolean isDeprecated;
private final boolean hasExtraAnnotations;
private final List<Class<? extends Annotation>> extraAnnotations;
private final GeneratedField<?>[] generatedFields;

GeneratedRecord(
final String simpleClassName,
final boolean isDeprecated,
final List<Class<? extends Annotation>> extraAnnotations,
final GeneratedField<?>... generatedFields) {
this.simpleClassName = simpleClassName;
this.isDeprecated = isDeprecated;
this.hasExtraAnnotations = !extraAnnotations.isEmpty();
this.extraAnnotations = extraAnnotations;
this.generatedFields = generatedFields;
}

Expand Down Expand Up @@ -137,4 +162,24 @@ public boolean isEnum() {
public GeneratedField<?>[] getGeneratedFields() {
return generatedFields;
}

/**
* {@inheritDoc}
*
* @return whether the class has extra annotations.
*/
@Override
public boolean hasExtraAnnotations() {
return hasExtraAnnotations;
}

/**
* {@inheritDoc}
*
* @return the collection of annotations.
*/
@Override
public List<Class<? extends Annotation>> getExtraAnnotations() {
return extraAnnotations;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,15 @@ private static void assertClassIsAnnotatedWith(
}
}

private static void assertClassIsAnnotatedWith(final Class<?> clazz, final Class<?> annotation) {
static void assertClassIsAnnotatedWith(final Class<?> clazz, final Class<?> annotation) {
Assertions.assertTrue(
Arrays.stream(clazz.getAnnotations())
.map(Annotation::annotationType)
.anyMatch(aClass -> aClass.equals(annotation)),
clazz.getCanonicalName() + " is NOT annotated with " + annotation.getCanonicalName());
}

private static void assertClassIsNotAnnotatedWith(
final Class<?> clazz, final Class<?> annotation) {
static void assertClassIsNotAnnotatedWith(final Class<?> clazz, final Class<?> annotation) {
Assertions.assertTrue(
Arrays.stream(clazz.getAnnotations())
.map(Annotation::annotationType)
Expand Down
Loading

0 comments on commit 90979fc

Please sign in to comment.