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

torand / openapi2java / 15494024830

06 Jun 2025 03:23PM UTC coverage: 82.388%. First build
15494024830

push

github

torand
refactor: replace util package with dep

503 of 716 branches covered (70.25%)

Branch coverage included in aggregate %.

7 of 14 new or added lines in 5 files covered. (50.0%)

1415 of 1612 relevant lines covered (87.78%)

4.77 hits per line

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

70.87
/src/main/java/io/github/torand/openapi2java/writers/java/JavaPojoWriter.java
1
/*
2
 * Copyright (c) 2024-2025 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.java;
17

18
import io.github.torand.openapi2java.generators.Options;
19
import io.github.torand.openapi2java.model.PojoInfo;
20
import io.github.torand.openapi2java.model.PropertyInfo;
21
import io.github.torand.openapi2java.writers.BaseWriter;
22
import io.github.torand.openapi2java.writers.PojoWriter;
23

24
import java.io.Writer;
25
import java.util.List;
26
import java.util.Set;
27
import java.util.TreeSet;
28
import java.util.concurrent.atomic.AtomicInteger;
29
import java.util.function.Consumer;
30
import java.util.function.Predicate;
31

32
import static io.github.torand.javacommons.collection.CollectionHelper.concatStream;
33
import static io.github.torand.javacommons.collection.CollectionHelper.nonEmpty;
34
import static java.util.Objects.nonNull;
35
import static java.util.function.Predicate.not;
36
import static java.util.stream.Collectors.joining;
37

38
/**
39
 * Writes Java code for a pojo.
40
 */
41
public class JavaPojoWriter extends BaseWriter implements PojoWriter {
42

43
    public JavaPojoWriter(Writer writer, Options opts) {
44
        super(writer, opts);
4✔
45
    }
1✔
46

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

52
        Set<String> nonJavaImports = new TreeSet<>();
4✔
53
        Set<String> javaImports = new TreeSet<>();
4✔
54

55
        Consumer<String> collectImport = qt -> { if (isJavaPackage(qt)) javaImports.add(qt); else nonJavaImports.add(qt);};
19✔
56
        Predicate<String> isModelType = qt -> isModelPackage(qt, pojoInfo.modelSubpackage);
10✔
57

58
        pojoInfo.imports.forEach(collectImport);
4✔
59
        pojoInfo.properties.stream()
4✔
60
            .flatMap(p -> p.imports.stream())
6✔
61
            .forEach(collectImport);
1✔
62
        pojoInfo.properties.stream()
4✔
63
            .flatMap(p -> p.type.typeImports())
6✔
64
            .filter(not(isModelType))
3✔
65
            .forEach(collectImport);
1✔
66
        pojoInfo.properties.stream()
4✔
67
            .flatMap(p -> p.type.annotationImports())
6✔
68
            .filter(not(isModelType))
3✔
69
            .forEach(collectImport);
1✔
70

71
        if (nonEmpty(nonJavaImports)) {
3!
72
            nonJavaImports.forEach(ti -> writeLine("import %s;".formatted(ti)));
17✔
73
            writeNewLine();
2✔
74
        }
75
        if (nonEmpty(javaImports)) {
3✔
76
            javaImports.forEach(ti -> writeLine("import %s;".formatted(ti)));
17✔
77
            writeNewLine();
2✔
78
        }
79

80
        if (pojoInfo.isDeprecated()) {
3!
81
            writeLine("/// @deprecated %s".formatted(pojoInfo.deprecationMessage));
×
82
            writeLine("@Deprecated");
×
83
        }
84

85
        pojoInfo.annotations.forEach(this::writeLine);
11✔
86

87
        if (opts.pojosAsRecords) {
4!
88
            writeLine("public record %s (".formatted(pojoInfo.name));
14✔
89
        } else {
90
            writeLine("public class %s {".formatted(pojoInfo.name));
×
91
        }
92

93
        AtomicInteger propNo = new AtomicInteger(1);
5✔
94
        pojoInfo.properties.forEach(propInfo -> {
7✔
95
            writeNewLine();
2✔
96
            writePropertyAnnotationLines(propInfo);
3✔
97

98
            writeIndent(1);
3✔
99
            if (nonNull(propInfo.type.itemType)) {
5✔
100
                String itemTypeWithAnnotations = concatStream(propInfo.type.itemType.annotations, List.of(propInfo.type.itemType.name))
11✔
101
                    .collect(joining(" "));
4✔
102

103
                if (!opts.pojosAsRecords) {
4!
104
                    write("public ");
×
105
                }
106

107
                if (nonNull(propInfo.type.keyType)) {
5!
NEW
108
                    String keyTypeWithAnnotations = concatStream(propInfo.type.keyType.annotations, List.of(propInfo.type.keyType.name))
×
109
                        .collect(joining(" "));
×
110

111
                    write("%s<%s, %s> %s".formatted(propInfo.type.name, keyTypeWithAnnotations, itemTypeWithAnnotations, propInfo.name));
×
112
                } else {
×
113
                    write("%s<%s> %s".formatted(propInfo.type.name, itemTypeWithAnnotations, propInfo.name));
23✔
114
                }
115
            } else {
1✔
116
                if (opts.pojosAsRecords) {
4!
117
                    write("%s %s".formatted(propInfo.type.name, propInfo.name));
20✔
118
                } else {
119
                    write("public %s %s".formatted(propInfo.type.name, propInfo.name));
×
120
                }
121
            }
122

123
            if (opts.pojosAsRecords) {
4!
124
                if (propNo.getAndIncrement() < pojoInfo.properties.size()) {
6✔
125
                    writeLine(",");
6✔
126
                } else {
127
                    writeNewLine();
3✔
128
                }
129
            } else {
130
                writeLine(";");
×
131
            }
132
        });
1✔
133

134
        if (opts.pojosAsRecords) {
4!
135
            writeLine(") {");
5✔
136
            writeNewLine();
2✔
137
            writeLine("}");
6✔
138
        } else {
139
            writeNewLine();
×
140
            writeNoArgConstructor(pojoInfo.name);
×
141
            writeNewLine();
×
142
            writeParameterizedConstructor(pojoInfo.name, pojoInfo.properties);
×
143
            writeLine("}");
×
144
        }
145
    }
1✔
146

147
    private void writeNoArgConstructor(String name) {
148
        writeIndent(1);
×
149
        writeLine("public %s() {", name);
×
150
        writeIndent(1);
×
151
        writeLine("}");
×
152
    }
×
153

154
    private void writeParameterizedConstructor(String name, List<PropertyInfo> props) {
155
        writeIndent(1);
×
156
        writeLine("public %s(%s) {", name, props.stream().map(p -> p.type.getFullName() + " " + p.name).collect(joining(", ")));
×
157
        props.forEach(p -> {
×
158
            writeIndent(2);
×
159
            writeLine("this.%s = %s;", p.name, p.name);
×
160
        });
×
161
        writeIndent(1);
×
162
        writeLine("}");
×
163
    }
×
164

165
    private void writePropertyAnnotationLines(PropertyInfo propInfo) {
166
        if (propInfo.isDeprecated()) {
3✔
167
            writeIndent(1);
3✔
168
            writeLine("/// @deprecated %s".formatted(propInfo.deprecationMessage));
13✔
169
            writeIndent(1);
3✔
170
            writeLine("@Deprecated");
5✔
171
        }
172
        propInfo.annotations.forEach(a -> {
5✔
173
            writeIndent(1);
3✔
174
            writeLine(a);
5✔
175
        });
1✔
176
        propInfo.type.annotations.forEach(a -> {
6✔
177
            writeIndent(1);
3✔
178
            writeLine(a);
5✔
179
        });
1✔
180
    }
1✔
181

182
    private boolean isModelPackage(String qualifiedType, String pojoModelSubpackage) {
183
        // Remove class name from qualifiedType value
184
        int lastDotIdx = qualifiedType.lastIndexOf(".");
4✔
185
        String typePackage = qualifiedType.substring(0, lastDotIdx);
5✔
186

187
        return opts.getModelPackage(pojoModelSubpackage).equals(typePackage);
7✔
188
    }
189

190
    private boolean isJavaPackage(String qualifiedType) {
191
        return qualifiedType.startsWith("java.");
4✔
192
    }
193
}
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