Skip to content

Commit

Permalink
Merge pull request #102 from cjbooms/ISSUE-101
Browse files Browse the repository at this point in the history
ISSUE-101: Add Support for @ReflectiveAccess Micronaut annotations
  • Loading branch information
averabaq authored Jan 4, 2022
2 parents 2501431 + 5638b7a commit 7439b36
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ This section documents the available CLI parameters for controlling what gets ge
| | `JAVA_SERIALIZATION` - This option adds Java Serializable interface to the generated models
| | `QUARKUS_REFLECTION` - This option adds @RegisterForReflection to the generated models. Requires dependency "'io.quarkus:quarkus-core:+"
| | `MICRONAUT_INTROSPECTION` - This option adds @Introspected to the generated models. Requires dependency "'io.micronaut:micronaut-core:+"
| | `MICRONAUT_REFLECTION` - This option adds @ReflectiveAccess to the generated models. Requires dependency "'io.micronaut:micronaut-core:+"
| `--output-directory` | Allows the generation dir to be overridden. Defaults to current dir
| `--targets` | Targets are the parts of the application that you want to be generated.
| | CHOOSE ANY OF:
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/com/cjbooms/fabrikt/cli/CodeGenOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ enum class ModelCodeGenOptionType(val description: String) {
X_EXTENSIBLE_ENUMS("This option treats x-extensible-enums as enums"),
JAVA_SERIALIZATION("This option adds Java Serializable interface to the generated models"),
QUARKUS_REFLECTION("This option adds @RegisterForReflection to the generated models. Requires dependency \"'io.quarkus:quarkus-core:+\""),
MICRONAUT_INTROSPECTION("This option adds @Introspected to the generated models. Requires dependency \"'io.micronaut:micronaut-core:+\"");
MICRONAUT_INTROSPECTION("This option adds @Introspected to the generated models. Requires dependency \"'io.micronaut:micronaut-core:+\""),
MICRONAUT_REFLECTION("This option adds @ReflectiveAccess to the generated models. Requires dependency \"'io.micronaut:micronaut-core:+\"");

override fun toString() = "`${super.toString()}` - $description"
}
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ class JacksonModelGenerator(
)
.addQuarkusReflectionAnnotation()
.addMicronautIntrospectedAnnotation()
.addMicronautReflectionAnnotation()
enum.entries.forEach {
classBuilder.addEnumConstant(
it.toEnumName(),
Expand Down Expand Up @@ -336,6 +337,7 @@ class JacksonModelGenerator(
.addSerializableInterface()
.addQuarkusReflectionAnnotation()
.addMicronautIntrospectedAnnotation()
.addMicronautReflectionAnnotation()
properties.addToClass(classBuilder, ClassType.VANILLA_MODEL)
return classBuilder.build()
}
Expand Down Expand Up @@ -367,6 +369,7 @@ class JacksonModelGenerator(
classBuilder.addAnnotation(polymorphicSubTypes(mappings, maybeEnumDiscriminator))
.addQuarkusReflectionAnnotation()
.addMicronautIntrospectedAnnotation()
.addMicronautReflectionAnnotation()

properties.addToClass(classBuilder, ClassType.SUPER_MODEL)

Expand All @@ -382,6 +385,7 @@ class JacksonModelGenerator(
.addSerializableInterface()
.addQuarkusReflectionAnnotation()
.addMicronautIntrospectedAnnotation()
.addMicronautReflectionAnnotation()
.superclass(
toModelType(packages.base, KotlinTypeInfo.from(superType.schema, superType.name))
)
Expand Down Expand Up @@ -423,18 +427,28 @@ class JacksonModelGenerator(
return this
}

private fun TypeSpec.Builder.addQuarkusReflectionAnnotation(): TypeSpec.Builder {
if (options.any { it == ModelCodeGenOptionType.QUARKUS_REFLECTION })
this.addAnnotation(
AnnotationSpec.builder("RegisterForReflection".toClassName("io.quarkus.runtime.annotations")).build()
)
return this
}
private fun TypeSpec.Builder.addQuarkusReflectionAnnotation(): TypeSpec.Builder =
this.addOptionalAnnotation(
ModelCodeGenOptionType.QUARKUS_REFLECTION,
"RegisterForReflection".toClassName("io.quarkus.runtime.annotations")
)

private fun TypeSpec.Builder.addMicronautIntrospectedAnnotation(): TypeSpec.Builder =
this.addOptionalAnnotation(
ModelCodeGenOptionType.MICRONAUT_INTROSPECTION,
"Introspected".toClassName("io.micronaut.core.annotation")
)

private fun TypeSpec.Builder.addMicronautReflectionAnnotation(): TypeSpec.Builder =
this.addOptionalAnnotation(
ModelCodeGenOptionType.MICRONAUT_REFLECTION,
"ReflectiveAccess".toClassName("io.micronaut.core.annotation")
)

private fun TypeSpec.Builder.addMicronautIntrospectedAnnotation(): TypeSpec.Builder {
if (options.any { it == ModelCodeGenOptionType.MICRONAUT_INTROSPECTION })
private fun TypeSpec.Builder.addOptionalAnnotation(optionType: ModelCodeGenOptionType, type: ClassName): TypeSpec.Builder {
if (options.any { it == optionType })
this.addAnnotation(
AnnotationSpec.builder("Introspected".toClassName("io.micronaut.core.annotation")).build()
AnnotationSpec.builder(type).build()
)
return this
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class ModelGeneratorTest {

@Test
fun `micronaut introspected models are generated from a full API definition when the micronaut-introspection option is set`() {
val basePackage = "examples.quarkusReflectionModels"
val basePackage = "examples.micronautIntrospectedModels"
val spec = readTextResource("/examples/micronautIntrospectedModels/api.yaml")
val expectedModels = readTextResource("/examples/micronautIntrospectedModels/models/Models.kt")

Expand All @@ -173,6 +173,23 @@ class ModelGeneratorTest {
assertThat(models).isEqualTo(expectedModels)
}

@Test
fun `micronaut reflection models are generated from a full API definition when the micronaut-reflection option is set`() {
val basePackage = "examples.micronautReflectionModels"
val spec = readTextResource("/examples/micronautReflectionModels/api.yaml")
val expectedModels = readTextResource("/examples/micronautReflectionModels/models/Models.kt")

val models = JacksonModelGenerator(
Packages(basePackage),
SourceApi(spec),
setOf(ModelCodeGenOptionType.MICRONAUT_REFLECTION)
)
.generate()
.toSingleFile()

assertThat(models).isEqualTo(expectedModels)
}

private fun Models.toSingleFile(): String {
val destPackage = if (models.isNotEmpty()) models.first().destinationPackage else ""
val singleFileBuilder = FileSpec.builder(destPackage, "dummyFilename")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package examples.quarkusReflectionModels.models
package examples.micronautIntrospectedModels.models

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonSubTypes
Expand Down
110 changes: 110 additions & 0 deletions src/test/resources/examples/micronautReflectionModels/api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
openapi: "3.0.0"
info:
paths:
components:
schemas:
QueryResult:
type: "object"
required:
- "items"
properties:
items:
type: "array"
minItems: 0
items:
oneOf:
- $ref: "#/components/schemas/FirstModel"
- $ref: "#/components/schemas/SecondModel"
- $ref: "#/components/schemas/ThirdModel"
Content:
type: "object"
required:
- "id"
- "attr_1"
- "attr_2"
- "attr_3"
- "etag"
- "model_type"
properties:
id:
description: "The unique resource id"
type: "string"
readOnly: true
first_attr:
description: "The attribute 1"
type: "string"
format: "date-time"
example: "2016-01-27T10:52:46.406Z"
readOnly: true
second_attr:
description: "The attribute 2"
type: "string"
readOnly: true
third_attr:
type: "string"
enum:
- "enum_type_1"
- "enum_type_2"
description: "Enum types for attribute 3"
example: "enum_type_2"
etag:
type: "string"
description: "Etag value to be used in conjunction with If-Match headers for optimistic locking purposes"
readOnly: true
model_type:
type: "string"
description: "The model discrimination type"
enum:
- "first_model"
- "second_model"
- "third_model"
example: "third_model"
discriminator:
propertyName: "model_type"
mapping:
first_model: "#/components/schemas/FirstModel"
second_model: "#/components/schemas/SecondModel"
third_model: "#/components/schemas/ThirdModel"

FirstModel:
allOf:
- $ref: "#/components/schemas/Content"
- type: "object"
properties:
extra_first_attr:
description: "The attribute 1 for model 1"
type: array
items:
type: "string"
minItems: 1
maxItems: 10
readOnly: true
SecondModel:
allOf:
- $ref: "#/components/schemas/Content"
- type: "object"
properties:
extra_first_attr:
description: "The attribute 1 for model 2"
type: "string"
readOnly: true
extra_second_attr:
description: "The attribute 2 for model 2"
type: boolean
readOnly: true

ThirdModel:
allOf:
- $ref: "#/components/schemas/Content"
- type: "object"
properties:
extra_first_attr:
description: "The attribute 1 for model 3"
type: "string"
format: "date-time"
example: "2016-01-27T10:52:46.406Z"
readOnly: true
extra_second_attr:
description: "The attribute 2 for model 3"
type: integer
readOnly: true
Loading

0 comments on commit 7439b36

Please sign in to comment.