The codegentle-common module provides the foundational interfaces and common functionality that all other Spec classes extend. These base interfaces define the core contracts and shared behavior across both Java and Kotlin code generation.
The root interface for all code specifications.
public interface SpecThis is the fundamental interface that all specification classes implement. It serves as a marker interface to identify code generation specifications and provides a common base for the type hierarchy.
Usage:
- All XxxSpec interfaces extend from this base
- Used for generic constraints and type safety
- No direct construction methods (abstract interface)
Extends both Spec and Named for specifications that have names.
public interface NamedSpec : Spec, NamedThis interface combines the specification marker with naming capability, making it suitable for any code element that has an identifiable name.
Properties:
- Inherits
name: StringfromNamedinterface - Provides identity and lookup capabilities
Used by:
- All type specifications (classes, interfaces, enums)
- Method and function specifications
- Field and property specifications
- Parameter specifications
Example Usage:
// NamedSpec is typically extended by concrete spec interfaces
interface MySpec : NamedSpec {
// Additional properties and methods
}The common module provides several collector interfaces that enable fluent builder APIs. These are mixed into spec builders to provide domain-specific functionality.
Provides documentation/javadoc/kdoc collection capabilities.
public interface DocCollector<T> {
fun addDoc(format: String, vararg args: CodeArgumentPart): T
fun addDoc(codeBlock: CodeValue): T
// Additional documentation methods
}Methods:
addDoc(format, ...args)- Add formatted documentationaddDoc(codeBlock)- Add pre-built code block documentation- Format string supports placeholders for arguments
Usage Example:
// In a spec builder that extends DocCollector
builder.addDoc("This is a documentation comment.")
builder.addDoc("Method with parameter %V", CodePart.type(someType))Collects initializer blocks for types that support them.
public interface InitializerBlockCollector<T> {
fun addInitializerBlock(format: String, vararg args: CodeArgumentPart): T
fun addInitializerBlock(codeBlock: CodeValue): T
}Methods:
addInitializerBlock(format, ...args)- Add formatted initializer codeaddInitializerBlock(codeBlock)- Add pre-built initializer block
Usage Example:
// Add initialization code that runs when instance is created
builder.addInitializerBlock("println(\"Object initialized\")")
builder.addInitializerBlock("this.field = defaultValue")Manages generic type parameters for types and methods.
public interface TypeVariableCollector<T> {
fun addTypeVariable(typeVariable: TypeRef<TypeVariableName>): T
fun addTypeVariables(typeVariables: Iterable<TypeRef<TypeVariableName>>): T
fun addTypeVariables(vararg typeVariables: TypeRef<TypeVariableName>): T
}Methods:
addTypeVariable(typeVariable)- Add single type parameteraddTypeVariables(iterable)- Add multiple type parameters from collectionaddTypeVariables(vararg)- Add multiple type parameters as varargs
Usage Example:
// Add generic type parameters like <T>, <T extends Something>
val tParam = TypeVariableName("T").ref()
val boundedParam = TypeVariableName("E", someInterface.ref()).ref()
builder.addTypeVariable(tParam)
builder.addTypeVariable(boundedParam)Collects annotation references for annotated elements.
public interface AnnotationRefCollector<T> {
fun addAnnotation(annotation: AnnotationRef): T
fun addAnnotations(annotations: Iterable<AnnotationRef>): T
fun addAnnotations(vararg annotations: AnnotationRef): T
}Methods:
addAnnotation(annotation)- Add single annotationaddAnnotations(iterable)- Add multiple annotations from collectionaddAnnotations(vararg)- Add multiple annotations as varargs
Usage Example:
// Add annotations like @Override, @Deprecated, etc.
val overrideAnnotation = JavaAnnotationNames.OVERRIDE.ref()
val deprecatedAnnotation = JavaAnnotationNames.DEPRECATED.ref()
builder.addAnnotation(overrideAnnotation)
builder.addAnnotations(overrideAnnotation, deprecatedAnnotation)Configures superclass relationships for types that support inheritance.
public interface SuperclassConfigurer<T> {
fun superclass(superclass: TypeName): T
fun superclass(superclass: TypeRef<*>): T
}Methods:
superclass(TypeName)- Set superclass by type namesuperclass(TypeRef)- Set superclass by type reference
Usage Example:
// Set superclass for a class that extends another
builder.superclass(ClassName("com.example", "BaseClass"))
builder.superclass(someClassRef)Collects interface implementations for types that can implement interfaces.
public interface SuperinterfaceCollector<T> {
fun addSuperinterface(superinterface: TypeName): T
fun addSuperinterface(superinterface: TypeRef<*>): T
fun addSuperinterfaces(superinterfaces: Iterable<TypeName>): T
// Additional overloads
}Methods:
addSuperinterface(TypeName/TypeRef)- Add single interface implementationaddSuperinterfaces(Iterable)- Add multiple interface implementations- Support for both
TypeNameandTypeRef<*>parameters
Usage Example:
// Add interface implementations
builder.addSuperinterface(ClassName("java.io", "Serializable"))
builder.addSuperinterface(someInterfaceRef)
val interfaces = listOf(
ClassName("java.lang", "Comparable"),
ClassName("java.lang", "Cloneable")
)
builder.addSuperinterfaces(interfaces)The collector interfaces follow a consistent pattern:
- Single Item Methods:
add[Item](item)for adding individual elements - Multiple Item Methods:
add[Items](iterable)andadd[Items](vararg)for bulk operations - Fluent Interface: All methods return the builder type
Tfor method chaining - Type Safety: Use strongly-typed parameters and generic constraints
These collectors are mixed into spec builders through interface inheritance:
// Example spec builder extending multiple collectors
public interface SomeSpecBuilder<T, B> :
DocCollector<B>,
TypeVariableCollector<B>,
AnnotationRefCollector<B> {
fun build(): T
}This approach provides:
- Composition over Inheritance: Mix only needed functionality
- Consistent API: Same method patterns across all collectors
- Type Safety: Strongly-typed builder chains
- Extensibility: Easy to add new collector types
These common interfaces are used consistently across Java and Kotlin modules:
// Java builders extend common collectors
public interface JavaMethodSpecBuilder :
DocCollector<JavaMethodSpecBuilder>,
TypeVariableCollector<JavaMethodSpecBuilder>,
JavaModifierCollector<JavaMethodSpecBuilder> // Java-specific// Kotlin builders extend common collectors
public interface KotlinFunctionSpecBuilder :
DocCollector<KotlinFunctionSpecBuilder>,
TypeVariableCollector<KotlinFunctionSpecBuilder>,
KotlinModifierCollector<KotlinFunctionSpecBuilder> // Kotlin-specific