Skip to content

Commit 136a044

Browse files
thejeff77claude
andcommitted
[kotlin-spring] Add companionObject option to generate companion objects in data classes
Extend the same companionObject option to the kotlin-spring server generator, enabling companion extensions on generated Spring model classes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6c623f2 commit 136a044

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
9898
public static final String USE_REQUEST_MAPPING_ON_INTERFACE = "useRequestMappingOnInterface";
9999
public static final String AUTO_X_SPRING_PAGINATED = "autoXSpringPaginated";
100100
public static final String USE_SEALED_RESPONSE_INTERFACES = "useSealedResponseInterfaces";
101+
public static final String COMPANION_OBJECT = "companionObject";
101102

102103
@Getter
103104
public enum DeclarativeInterfaceReactiveMode {
@@ -163,6 +164,7 @@ public String getDescription() {
163164
@Setter private boolean useResponseEntity = true;
164165
@Setter private boolean autoXSpringPaginated = false;
165166
@Setter private boolean useSealedResponseInterfaces = false;
167+
@Setter private boolean companionObject = false;
166168

167169
@Getter @Setter
168170
protected boolean useSpringBoot3 = false;
@@ -265,6 +267,7 @@ public KotlinSpringServerCodegen() {
265267
addOption(SCHEMA_IMPLEMENTS, "A map of single interface or a list of interfaces per schema name that should be implemented (serves similar purpose as `x-kotlin-implements`, but is fully decoupled from the api spec). Example: yaml `schemaImplements: {Pet: com.some.pack.WithId, Category: [com.some.pack.CategoryInterface], Dog: [com.some.pack.Canine, com.some.pack.OtherInterface]}` implements interfaces in schemas `Pet` (interface `com.some.pack.WithId`), `Category` (interface `com.some.pack.CategoryInterface`), `Dog`(interfaces `com.some.pack.Canine`, `com.some.pack.OtherInterface`)", "empty map");
266268
addOption(SCHEMA_IMPLEMENTS_FIELDS, "A map of single field or a list of fields per schema name that should be prepended with `override` (serves similar purpose as `x-kotlin-implements-fields`, but is fully decoupled from the api spec). Example: yaml `schemaImplementsFields: {Pet: id, Category: [name, id], Dog: [bark, breed]}` marks fields to be prepended with `override` in schemas `Pet` (field `id`), `Category` (fields `name`, `id`) and `Dog` (fields `bark`, `breed`)", "empty map");
267269
addSwitch(AUTO_X_SPRING_PAGINATED, "Automatically add x-spring-paginated to operations that have 'page', 'size', and 'sort' query parameters. When enabled, operations with all three parameters will have Pageable support automatically applied. Operations with x-spring-paginated explicitly set to false will not be auto-detected.", autoXSpringPaginated);
270+
addSwitch(COMPANION_OBJECT, "Whether to generate companion objects in data classes, enabling companion extensions.", companionObject);
268271
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
269272
supportedLibraries.put(SPRING_CLOUD_LIBRARY,
270273
"Spring-Cloud-Feign client with Spring-Boot auto-configured settings.");
@@ -512,6 +515,12 @@ public void processOpts() {
512515
}
513516
writePropertyBack(USE_SEALED_RESPONSE_INTERFACES, useSealedResponseInterfaces);
514517

518+
if (additionalProperties.containsKey(COMPANION_OBJECT)) {
519+
this.setCompanionObject(convertPropertyToBooleanAndWriteBack(COMPANION_OBJECT));
520+
} else {
521+
additionalProperties.put(COMPANION_OBJECT, companionObject);
522+
}
523+
515524
additionalProperties.put("springHttpStatus", new SpringHttpStatusLambda());
516525

517526
// Set basePackage from invokerPackage

modules/openapi-generator/src/main/resources/kotlin-spring/dataClass.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@
6464
private const val serialVersionUID: kotlin.Long = 1
6565
}
6666
{{/serializableModel}}
67-
}
67+
{{^serializableModel}}{{#companionObject}} companion object { }
68+
{{/companionObject}}{{/serializableModel}}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4706,6 +4706,35 @@ public void testDeprecatedAnnotationOnController() throws IOException {
47064706
"@Deprecated(message=\"Operation is deprecated\") @RequestMapping("
47074707
);
47084708
}
4709+
4710+
@Test
4711+
public void testCompanionObjectDefaultIsFalse() {
4712+
final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
4713+
codegen.processOpts();
4714+
4715+
Assert.assertEquals(codegen.additionalProperties().get(COMPANION_OBJECT), false);
4716+
}
4717+
4718+
@Test
4719+
public void testCompanionObjectGeneratesCompanionInModel() throws IOException {
4720+
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
4721+
output.deleteOnExit();
4722+
String outputPath = output.getAbsolutePath().replace('\\', '/');
4723+
4724+
KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
4725+
codegen.setOutputDir(output.getAbsolutePath());
4726+
codegen.additionalProperties().put(COMPANION_OBJECT, true);
4727+
4728+
new DefaultGenerator().opts(new ClientOptInput()
4729+
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/petstore.yaml"))
4730+
.config(codegen))
4731+
.generate();
4732+
4733+
assertFileContains(
4734+
Paths.get(outputPath + "/src/main/kotlin/org/openapitools/model/Pet.kt"),
4735+
"companion object { }"
4736+
);
4737+
}
47094738
}
47104739

47114740

0 commit comments

Comments
 (0)