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

torand / jsonschema2java / 18399814123

10 Oct 2025 07:35AM UTC coverage: 78.214% (-0.9%) from 79.157%
18399814123

push

github

torand
fix: bean validation annotations on primitive subtypes of compound pojo property types now generated

287 of 413 branches covered (69.49%)

Branch coverage included in aggregate %.

440 of 533 new or added lines in 26 files covered. (82.55%)

1 existing line in 1 file now uncovered.

808 of 987 relevant lines covered (81.86%)

4.75 hits per line

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

72.48
/src/main/java/io/github/torand/jsonschema2java/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.jsonschema2java.writers.java;
17

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

25
import java.io.Writer;
26
import java.util.List;
27
import java.util.concurrent.atomic.AtomicInteger;
28

29
import static io.github.torand.javacommons.collection.CollectionHelper.nonEmpty;
30
import static java.util.function.Predicate.not;
31
import static java.util.stream.Collectors.joining;
32

33
/**
34
 * Writes Java code for a pojo.
35
 */
36
public class JavaPojoWriter extends BaseWriter implements PojoWriter {
37

38
    public JavaPojoWriter(Writer writer, Options opts) {
39
        super(writer, opts);
4✔
40
    }
1✔
41

42
    @Override
43
    public void write(PojoInfo pojoInfo) {
44
        writeLine("package %s;", opts.getModelPackage(pojoInfo.modelSubpackage()));
13✔
45
        writeNewLine();
2✔
46

47
        writeNonJavaImports(pojoInfo);
3✔
48
        writeJavaImports(pojoInfo);
3✔
49

50
        if (pojoInfo.isDeprecated()) {
3!
NEW
51
            writeLine("/// @deprecated %s".formatted(pojoInfo.deprecationMessage()));
×
52
            writeLine("@Deprecated");
×
53
        }
54

55
        pojoInfo.annotations().forEach(a -> writeLine(a.annotation()));
12✔
56

57
        if (opts.pojosAsRecords()) {
4!
58
            writeLine("public record %s (".formatted(pojoInfo.name()));
14✔
59
        } else {
NEW
60
            writeLine("public class %s {".formatted(pojoInfo.name()));
×
61
        }
62

63
        AtomicInteger propNo = new AtomicInteger(1);
5✔
64
        pojoInfo.properties().forEach(propInfo -> {
7✔
65
            writeNewLine();
2✔
66
            writePropertyAnnotationLines(propInfo);
3✔
67
            writePropertyTypeAndNameLines(propInfo);
3✔
68

69
            if (opts.pojosAsRecords()) {
4!
70
                if (propNo.getAndIncrement() < pojoInfo.properties().size()) {
6✔
71
                    writeLine(",");
6✔
72
                } else {
73
                    writeNewLine();
3✔
74
                }
75
            } else {
76
                writeLine(";");
×
77
            }
78
        });
1✔
79

80
        if (opts.pojosAsRecords()) {
4!
81
            writeLine(") {");
5✔
82
            writeNewLine();
2✔
83
            writeLine("}");
6✔
84
        } else {
85
            writeNewLine();
×
NEW
86
            writeNoArgConstructor(pojoInfo.name());
×
87
            writeNewLine();
×
NEW
88
            writeParameterizedConstructor(pojoInfo.name(), pojoInfo.properties());
×
89
            writeLine("}");
×
90
        }
91
    }
1✔
92

93
    private void writeJavaImports(PojoInfo pojoInfo) {
94
        List<String> imports = pojoInfo.aggregatedNormalImports().stream()
5✔
95
            .filter(this::isJavaPackage)
3✔
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 writeNonJavaImports(PojoInfo pojoInfo) {
106
        List<String> imports = pojoInfo.aggregatedNormalImports().stream()
5✔
107
            .filter(not(this::isJavaPackage))
5✔
108
            .filter(ni -> !isInPackage(ni, pojoInfo.modelSubpackage()))
13✔
109
            .map("import %s;"::formatted)
10✔
110
            .toList();
2✔
111

112
        if (nonEmpty(imports)) {
3!
113
            imports.forEach(this::writeLine);
10✔
114
            writeNewLine();
2✔
115
        }
116
    }
1✔
117

118
    private void writeNoArgConstructor(String name) {
119
        writeIndent(1);
×
120
        writeLine("public %s() {", name);
×
121
        writeIndent(1);
×
122
        writeLine("}");
×
123
    }
×
124

125
    private void writeParameterizedConstructor(String name, List<PropertyInfo> props) {
126
        writeIndent(1);
×
NEW
127
        writeLine("public %s(%s) {", name, props.stream().map(p -> p.type().getFullName() + " " + p.name()).collect(joining(", ")));
×
128
        props.forEach(p -> {
×
129
            writeIndent(2);
×
NEW
130
            writeLine("this.%s = %s;", p.name(), p.name());
×
131
        });
×
132
        writeIndent(1);
×
133
        writeLine("}");
×
134
    }
×
135

136
    private void writePropertyAnnotationLines(PropertyInfo propInfo) {
137
        if (propInfo.isDeprecated()) {
3✔
138
            writeIndent(1);
3✔
139
            writeLine("/// @deprecated %s".formatted(propInfo.deprecationMessage()));
13✔
140
            writeIndent(1);
3✔
141
            writeLine("@Deprecated");
5✔
142
        }
143
        propInfo.annotations().forEach(a -> {
5✔
144
            writeIndent(1);
3✔
145
            writeLine(a.annotation());
6✔
146
        });
1✔
147
    }
1✔
148

149
    private void writePropertyTypeAndNameLines(PropertyInfo propInfo) {
150
        AnnotatedTypeName annotatedTypeName = propInfo.type().getAnnotatedFullName();
4✔
151

152
        annotatedTypeName.annotations().forEach(a -> {
5✔
153
            writeIndent(1);
3✔
154
            writeLine(a);
5✔
155
        });
1✔
156

157
        writeIndent(1);
3✔
158
        if (opts.pojosAsRecords()) {
4!
159
            write("%s %s".formatted(annotatedTypeName.typeName(), propInfo.name()));
19✔
160
        } else {
NEW
161
            write("public %s %s".formatted(annotatedTypeName.typeName(), propInfo.name()));
×
162
        }
163
    }
1✔
164

165
    private boolean isInPackage(String qualifiedType, String pojoModelSubpackage) {
166
        // Remove class name from qualifiedType value
167
        int lastDotIdx = qualifiedType.lastIndexOf(".");
4✔
168
        String typePackage = qualifiedType.substring(0, lastDotIdx);
5✔
169

170
        return opts.getModelPackage(pojoModelSubpackage).equals(typePackage);
7✔
171
    }
172

173
    private boolean isJavaPackage(String qualifiedType) {
174
        return qualifiedType.startsWith("java.");
4✔
175
    }
176
}
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