• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

torand / openapi2java / 22519240185

28 Feb 2026 10:47AM UTC coverage: 84.535% (+0.1%) from 84.425%
22519240185

push

github

torand
chore: prepare release

572 of 795 branches covered (71.95%)

Branch coverage included in aggregate %.

1702 of 1895 relevant lines covered (89.82%)

5.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.05
/src/main/java/io/github/torand/openapi2java/writers/kotlin/KotlinPojoWriter.java
1
/*
2
 * Copyright (c) 2024-2026 Tore Eide Andersen
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package io.github.torand.openapi2java.writers.kotlin;
17

18
import io.github.torand.openapi2java.generators.Options;
19
import io.github.torand.openapi2java.model.AnnotatedTypeName;
20
import io.github.torand.openapi2java.model.AnnotationInfo;
21
import io.github.torand.openapi2java.model.PojoInfo;
22
import io.github.torand.openapi2java.model.PropertyInfo;
23
import io.github.torand.openapi2java.utils.PackageUtils;
24
import io.github.torand.openapi2java.writers.BaseWriter;
25
import io.github.torand.openapi2java.writers.PojoWriter;
26

27
import java.io.Writer;
28
import java.util.List;
29
import java.util.Set;
30
import java.util.concurrent.atomic.AtomicInteger;
31
import java.util.function.Predicate;
32

33
import static io.github.torand.javacommons.collection.CollectionHelper.isEmpty;
34
import static io.github.torand.javacommons.collection.CollectionHelper.nonEmpty;
35
import static io.github.torand.javacommons.stream.StreamHelper.streamSafely;
36
import static io.github.torand.openapi2java.utils.KotlinTypeMapper.toKotlinNative;
37
import static io.github.torand.openapi2java.utils.PackageUtils.isFqnInPackage;
38
import static java.util.function.Predicate.not;
39

40
/**
41
 * Writes Kotlin code for a pojo.
42
 */
43
public class KotlinPojoWriter extends BaseWriter implements PojoWriter {
44

45
    public KotlinPojoWriter(Writer writer, Options opts) {
46
        super(writer, opts);
4✔
47
    }
1✔
48

49
    @Override
50
    public void write(PojoInfo pojoInfo) {
51
        writeLine("package %s", opts.getModelPackage(pojoInfo.modelSubpackage()));
13✔
52
        writeNewLine();
2✔
53

54
        writeImports(pojoInfo);
3✔
55

56
        if (pojoInfo.isDeprecated()) {
3!
57
            writeLine("@Deprecated(\"%s\")".formatted(pojoInfo.deprecationMessage()));
×
58
        }
59

60
        pojoInfo.annotations().forEach(a -> writeLine(a.annotation()));
12✔
61
        writeLine("@JvmRecord");
5✔
62

63
        writeLine("data class %s (".formatted(pojoInfo.name()));
13✔
64

65
        if (isEmpty(pojoInfo.properties())) {
4✔
66
            // Empty data classes not allowed in Kotlin
67
            writeNewLine();
2✔
68
            writeIndent(1);
3✔
69
            writeLine("val placeholder: String = \"\"");
6✔
70
        } else {
71
            AtomicInteger propNo = new AtomicInteger(1);
5✔
72
            pojoInfo.properties().forEach(propInfo -> {
7✔
73
                writeNewLine();
2✔
74
                writePropertyAnnotationLines(propInfo);
3✔
75
                writePropertyTypeAndName(propInfo);
3✔
76

77
                if (propNo.getAndIncrement() < pojoInfo.properties().size()) {
6✔
78
                    writeLine(",");
6✔
79
                } else {
80
                    writeNewLine();
2✔
81
                }
82
            });
1✔
83
        }
84

85
        writeLine(")");
5✔
86
    }
1✔
87

88
    private void writeImports(PojoInfo pojoInfo) {
89
        Predicate<String> isInSamePackage = fqn -> isFqnInPackage(fqn, opts.getModelPackage(pojoInfo.modelSubpackage()));
12✔
90

91
        List<String> imports = pojoInfo.aggregatedNormalImports().stream()
4✔
92
            .filter(not(PackageUtils::isFundamentalJavaClass))
3✔
93
            .filter(not(isInSamePackage))
4✔
94
            .filter(not("java.util.List"::equals))
4✔
95
            .filter(not("java.util.Map"::equals))
4✔
96
            .map("import %s"::formatted)
10✔
97
            .toList();
2✔
98

99
        if (nonEmpty(imports)) {
3!
100
            imports.forEach(this::writeLine);
10✔
101
            writeNewLine();
2✔
102
        }
103
    }
1✔
104

105
    private void writePropertyAnnotationLines(PropertyInfo propInfo) {
106
        if (propInfo.isDeprecated()) {
3✔
107
            writeIndent(1);
3✔
108
            writeLine("@Deprecated(\"%s\")".formatted(propInfo.deprecationMessage()));
13✔
109
        }
110
        streamSafely(propInfo.annotations())
4✔
111
            .map(AnnotationInfo::annotation)
3✔
112
            .map(this::prefixPropertyAnnotation)
3✔
113
            .forEach(a -> {
1✔
114
                writeIndent(1);
3✔
115
                writeLine(a);
5✔
116
            });
1✔
117
    }
1✔
118

119
    private void writePropertyTypeAndName(PropertyInfo propInfo) {
120
        AnnotatedTypeName annotatedTypeName = propInfo.type().getAnnotatedFullName();
4✔
121

122
        annotatedTypeName.annotations()
4✔
123
            .map(this::prefixPropertyAnnotation)
3✔
124
            .forEach(a -> {
1✔
125
                writeIndent(1);
3✔
126
                writeLine(a);
5✔
127
            });
1✔
128

129
        writeIndent(1);
3✔
130
        write("val %s: ", escapeReservedKeywords(propInfo.name()));
11✔
131
        write(toKotlinNative(annotatedTypeName.typeName()));
7✔
132

133
        if (!propInfo.required() || propInfo.type().nullable()) {
7!
134
            write("? = null");
5✔
135
        }
136
    }
1✔
137

138
    private String prefixPropertyAnnotation(String annotation) {
139
        if (annotation.startsWith("@JsonProperty")) {
4✔
140
            return annotation;
2✔
141
        }
142

143
        return "@field:"+annotation.substring(1);
5✔
144
    }
145

146
    private static String escapeReservedKeywords(String name) {
147
        return RESERVED_KEYWORDS.contains(name) ? "`%s`".formatted(name) : name;
6!
148
    }
149

150
    private static final Set<String> RESERVED_KEYWORDS = Set.of(
117✔
151
        "as", "break", "class", "continue", "do", "else", "false", "for", "fun", "if", "in", "interface",
152
        "is", "null", "object", "package", "return", "super", "this", "throw", "true", "try", "typealias",
153
        "typeof", "val", "var", "when", "while"
154
    );
155
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc