Analyzing Types (Reflection)
Type analysis is the first step to generating a schema. The step looks at all involved Kotlin or Java types and extracts information about methods, fields, subtypes, supertypes, type parameters and more.
Using Kotlinx.Serialization
Information about type analysis using Kotlinx.Serialization
Basics
class ExampleClass(
val text: String,
val number: Int?
)../
With the analyzeTypeUsingReflection()-step, information about a given input type is extracted and resulting
information about the type as well as other referenced types, e.g. "ExampleClass", "String" and "Int" is returned to be used as inputs
for further steps.
The step can be configured to specify which information should be included in the output and in what format.
initial<ExampleClass>().analyzeTypeUsingReflection {
//...
}
Configuration Options
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
Inheritance and Subtypes
Sealed Class and Interfaces
Subtypes of sealed classes and interfaces are detected and included automatically.
sealed class SealedParent { //(1)!
class ChildOne : SealedParent()
class ChildTwo : SealedParent()
}
- Sealed class
SealedParentwith two subtypesChildOneandChildTwo.
initial<SealedParent>().analyzeTypeUsingReflection()
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
Manually Including Subtypes
When using classes that are not "sealed", subtypes are not automatically detected and have to be added as input types for them to be respected in the analysis.
open class ParentManual { //(1)!
class ChildOne : ParentManual()
class ChildTwo : ParentManual()
}
- Class
ParentManualwith two subtypesChildOneandChildTwo.
initial<ParentManual>( //(1)!
listOf(
typeOf<ParentManual.ChildOne>(), //(2)!
typeOf<ParentManual.ChildTwo>()
)
)
.analyzeTypeUsingReflection() //(3)!
.addMissingSupertypeSubtypeRelations() //(4)!
- The main type we want to analyze and get information for.
- Additional types we want to include when extracting information.
- Extract information from all input types individually, i.e. from
ParentManual,ChildOne,ChildTwo ChildOneandChildTworeferenceParentManualas their supertype, butParentManualdoes not yet know about its subtypes.This step finds and fills in these missing connections, i.e. addsChildOneandChildTwoto the subtypes ofParentManual.
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-core:$version")
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation 'io.github.smiley4:schema-kenerator-core:$version'
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-core</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
Core @Subtype-Annotation
Instead of adding the possible subtypes to the input manually, they can be connected automatically using the schema-kenerator-core @SubType-annotation.
@SubType(ParentCore.ChildOne::class) //(1)!
@SubType(ParentCore.ChildTwo::class)
open class ParentCore { //(2)!
class ChildOne : ParentCore()
class ChildTwo : ParentCore()
}
- All subtypes defined on the parent class using
@SubType-annotations. - Class
ParentManualwith two subtypesChildOneandChildTwo.
initial<ParentCore>()
.collectSubTypes() //(1)!
.analyzeTypeUsingReflection()
.addMissingSupertypeSubtypeRelations() //(2)!
- This step looks at the
@SubType-annotations present on any input type (recursive) and adds the referenced types to be included as inputs in the next steps. ChildOneandChildTworeferenceParentCoreas their supertype, butParentCoredoes not yet know about its subtypes.This step finds and fills in these missing connections, i.e. addsChildOneandChildTwoto the subtypes ofParentCore.
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-core:$version")
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation 'io.github.smiley4:schema-kenerator-core:$version'
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-core</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
Jackson @JsonSubTypes-Annotation
Instead of adding the possible subtypes to the input manually, they can also be connected automatically using the Jackson @JsonSubTypes-annotation.
@JsonSubTypes(
JsonSubTypes.Type(value = ParentJackson.ChildOne::class), //(1)!
JsonSubTypes.Type(value = ParentJackson.ChildTwo::class),
)
open class ParentJackson { //(2)!
class ChildOne : ParentJackson()
class ChildTwo : ParentJackson()
}
- All subtypes defined on the parent class using
@JsonSubTypes-annotation. - Class
ParentJacksonwith two subtypesChildOneandChildTwo.
initial<ParentJackson>()
.collectJacksonSubTypes({ //(1)!
it.analyzeTypeUsingReflection() //(2)!
})
.analyzeTypeUsingReflection()
.addMissingSupertypeSubtypeRelations() //(3)!
- The "collectJacksonSubTypes()"-step looks at the @JsonSubTypes-annotation present on any type (recursive) and adds the referenced types to be included in the next steps.
- this step needs to intermediate information from the types. This specifies how this information is extracted. reflection is recommended here.
ChildOneandChildTworeferenceParentJacksonas their supertype, butParentJacksondoes not yet know about its subtypes.This step finds and fills in these missing connections, i.e. addsChildOneandChildTwoto the subtypes ofParentJackson.
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation("io.github.smiley4:schema-kenerator-jackson:$version")
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
implementation 'io.github.smiley4:schema-kenerator-jackson:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-jackson</artifactId>
<version>${version}</version>
</dependency>
Discriminator Properties
A discriminator is used to differentiate between subtypes when (de-)serializing types, i.e. to know which subtype we are dealing with. This property is often times not included as a field in the class itself, but configured e.g. via an annotation. This property can also be added to the type information, e.g. to be later included in generated schemas.
Default Property
sealed class SealedParent { //(1)!
class ChildOne : SealedParent()
class ChildTwo : SealedParent()
}
- Class
SealedParentwith two subtypesChildOneandChildTwoto differentiate between.
initial<SealedParent>()
.analyzeTypeUsingReflection()
.addDiscriminatorProperty("_type") //(1)!
- Makes sure a property
_typeexists for all types that have subtypes.
An "annotation" with name discriminator_marker is added to the property to mark it and make it possible to find it later, e.g. when generating schemas.
If a property with the name already exists, the maker annotation is added to this property instead.
If a (different) property with marked with the annotation is already present, the step will NOT add the new specified property.
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-core:$version")
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation 'io.github.smiley4:schema-kenerator-core:$version'
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-core</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
Jackson @JsonTypeInfo-annotation
A discriminator property with a name specified with the Jackson @JsonClassDiscriminator-annotation can be added to all types that have known subtypes.
Only @JsonTypeInfo#include "PROPERTY" and "EXISTING_PROPERTY" is supported.
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, //(1)!
property = "_type" //(2)!
)
sealed class ParentDiscriminatorJackson { //(3)!
class ChildOne : SealedParent()
class ChildTwo : SealedParent()
}
- Specify how to include the (new) property. Only
PROPERTYandEXISTING_PROPERTYare currently supported. - Specify the name of the (new) property.
- Class
ParentDiscriminatorJacksonwith two subtypesChildOneandChildTwoto differentiate between.
initial<ParentDiscriminatorJackson>()
.analyzeTypeUsingReflection()
.addJacksonTypeInfoDiscriminatorProperty() //(1)!
- Adds a property with the name specified in
@JsonTypeInfo#propertyto all annotated types with subtypes.
An "annotation" with name discriminator_marker is added to the property to mark it and make it possible to find it later, e.g. when generating schemas.
If a property with the name already exists, the maker annotation is added to this property instead.
If a (different) property with marked with the annotation is already present, the step will NOT add the new specified property.
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-reflection:$version")
implementation("io.github.smiley4:schema-kenerator-jackson:$version")
implementation 'io.github.smiley4:schema-kenerator-reflection:$version'
implementation 'io.github.smiley4:schema-kenerator-jackson:$version'
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-reflection</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>io.github.smiley4</groupId>
<artifactId>schema-kenerator-jackson</artifactId>
<version>${version}</version>
</dependency>