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
SealedParent
with two subtypesChildOne
andChildTwo
.
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
ParentManual
with two subtypesChildOne
andChildTwo
.
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
ChildOne
andChildTwo
referenceParentManual
as their supertype, butParentManual
does not yet know about its subtypes.This step finds and fills in these missing connections, i.e. addsChildOne
andChildTwo
to 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
ParentManual
with two subtypesChildOne
andChildTwo
.
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. ChildOne
andChildTwo
referenceParentCore
as their supertype, butParentCore
does not yet know about its subtypes.This step finds and fills in these missing connections, i.e. addsChildOne
andChildTwo
to 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
ParentJackson
with two subtypesChildOne
andChildTwo
.
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.
ChildOne
andChildTwo
referenceParentJackson
as their supertype, butParentJackson
does not yet know about its subtypes.This step finds and fills in these missing connections, i.e. addsChildOne
andChildTwo
to 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
SealedParent
with two subtypesChildOne
andChildTwo
to differentiate between.
initial<SealedParent>()
.analyzeTypeUsingReflection()
.addDiscriminatorProperty("_type") //(1)!
- Makes sure a property
_type
exists 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
PROPERTY
andEXISTING_PROPERTY
are currently supported. - Specify the name of the (new) property.
- Class
ParentDiscriminatorJackson
with two subtypesChildOne
andChildTwo
to differentiate between.
initial<ParentDiscriminatorJackson>()
.analyzeTypeUsingReflection()
.addJacksonTypeInfoDiscriminatorProperty() //(1)!
- Adds a property with the name specified in
@JsonTypeInfo#property
to 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>