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

mybatis / generator / 1942

12 Jan 2026 05:01PM UTC coverage: 88.75% (+0.4%) from 88.365%
1942

push

github

web-flow
Merge pull request #1412 from jeffgbutler/jspecify

Adopt JSpecify

2331 of 3162 branches covered (73.72%)

1800 of 1949 new or added lines in 202 files covered. (92.36%)

18 existing lines in 10 files now uncovered.

11384 of 12827 relevant lines covered (88.75%)

0.89 hits per line

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

64.53
/core/mybatis-generator-core/src/main/java/org/mybatis/generator/internal/DomWriter.java
1
/*
2
 *    Copyright 2006-2026 the original author or authors.
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
 *       https://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 org.mybatis.generator.internal;
17

18
import static org.mybatis.generator.internal.util.messages.Messages.getString;
19

20
import java.io.PrintWriter;
21
import java.io.StringWriter;
22

23
import org.jspecify.annotations.Nullable;
24
import org.mybatis.generator.exception.ShellException;
25
import org.w3c.dom.Attr;
26
import org.w3c.dom.CDATASection;
27
import org.w3c.dom.Comment;
28
import org.w3c.dom.Document;
29
import org.w3c.dom.DocumentType;
30
import org.w3c.dom.Element;
31
import org.w3c.dom.EntityReference;
32
import org.w3c.dom.NamedNodeMap;
33
import org.w3c.dom.Node;
34
import org.w3c.dom.ProcessingInstruction;
35
import org.w3c.dom.Text;
36

37
/**
38
 * This class is used to generate a String representation of an XML document. It
39
 * is very much based on the class dom.Writer from the Apache Xerces examples,
40
 * but I've simplified and updated it.
41
 *
42
 * @author Andy Clark, IBM (Original work)
43
 * @author Jeff Butler (derivation)
44
 */
45
public class DomWriter {
46
    protected final PrintWriter printWriter;
47
    protected final StringWriter sw;
48
    protected final Document document;
49
    protected boolean isXML11;
50

51
    public DomWriter(Document document) {
1✔
52
        sw = new StringWriter();
1✔
53
        printWriter = new PrintWriter(sw);
1✔
54
        this.document = document;
1✔
55
    }
1✔
56

57
    public synchronized String getFormattedDocument() throws ShellException {
58
        write(document);
1✔
59
        return sw.toString();
1✔
60
    }
61

62
    protected Attr[] sortAttributes(@Nullable NamedNodeMap attrs) {
63
        int len = (attrs != null) ? attrs.getLength() : 0;
1!
64
        Attr[] array = new Attr[len];
1✔
65
        for (int i = 0; i < len; i++) {
1✔
66
            array[i] = (Attr) attrs.item(i);
1✔
67
        }
68
        for (int i = 0; i < len - 1; i++) {
1✔
69
            String name = array[i].getNodeName();
1✔
70
            int index = i;
1✔
71
            for (int j = i + 1; j < len; j++) {
1✔
72
                String curName = array[j].getNodeName();
1✔
73
                if (curName.compareTo(name) < 0) {
1!
74
                    name = curName;
×
75
                    index = j;
×
76
                }
77
            }
78
            if (index != i) {
1!
79
                Attr temp = array[i];
×
80
                array[i] = array[index];
×
81
                array[index] = temp;
×
82
            }
83
        }
84

85
        return array;
1✔
86
    }
87

88
    protected void normalizeAndPrint(@Nullable String s, boolean isAttValue) {
89
        int len = (s != null) ? s.length() : 0;
1!
90
        for (int i = 0; i < len; i++) {
1✔
91
            char c = s.charAt(i);
1✔
92
            normalizeAndPrint(c, isAttValue);
1✔
93
        }
94
    }
1✔
95

96
    protected void normalizeAndPrint(char c, boolean isAttValue) {
97

98
        switch (c) {
1!
99
        case '<':
100
            handleLessThan();
×
101
            break;
×
102
        case '>':
103
            handleGreaterThan();
×
104
            break;
×
105
        case '&':
106
            handleAmpersand();
×
107
            break;
×
108
        case '"':
109
            handleDoubleQuote(isAttValue);
×
110
            break;
×
111
        case '\r':
112
            handleCarriageReturn();
×
113
            break;
×
114
        case '\n':
115
            handleLineFeed();
1✔
116
            break;
1✔
117
        default:
118
            handleDefault(c, isAttValue);
1✔
119
        }
120
    }
1✔
121

122
    private void handleDefault(char c, boolean isAttValue) {
123
        // In XML 1.1, control chars in the ranges [#x1-#x1F, #x7F-#x9F]
124
        // must be escaped.
125
        //
126
        // Escape space characters that would be normalized to #x20 in
127
        // attribute values
128
        // when the document is reparsed.
129
        //
130
        // Escape NEL (0x85) and LSEP (0x2028) that appear in content
131
        // if the document is XML 1.1, since they would be normalized to LF
132
        // when the document is reparsed.
133
        if (isXML11
1!
134
                && ((c >= 0x01 && c <= 0x1F && c != 0x09 && c != 0x0A)
135
                        || (c >= 0x7F && c <= 0x9F) || c == 0x2028)
136
                || isAttValue && (c == 0x09 || c == 0x0A)) {
137
            printWriter.print("&#x"); //$NON-NLS-1$
×
138
            printWriter.print(Integer.toHexString(c).toUpperCase());
×
139
            printWriter.print(';');
×
140
        } else {
141
            printWriter.print(c);
1✔
142
        }
143
    }
1✔
144

145
    private void handleLineFeed() {
146
        // If LF is part of the document's content, it
147
        // should be printed back out with the system default
148
        // line separator.  XML parsing forces \n only after a parse,
149
        // but we should write it out as it was to avoid whitespace
150
        // commits on some version control systems.
151
        printWriter.print(System.lineSeparator());
1✔
152
    }
1✔
153

154
    private void handleCarriageReturn() {
155
        // If CR is part of the document's content, it
156
        // must be printed as a literal otherwise
157
        // it would be normalized to LF when the document
158
        // is reparsed.
159
        printWriter.print("&#xD;"); //$NON-NLS-1$
×
160
    }
×
161

162
    private void handleDoubleQuote(boolean isAttValue) {
163
        // A '"' that appears in character data
164
        // does not need to be escaped.
165
        if (isAttValue) {
×
166
            printWriter.print("&quot;"); //$NON-NLS-1$
×
167
        } else {
168
            printWriter.print('"');
×
169
        }
170
    }
×
171

172
    private void handleAmpersand() {
173
        printWriter.print("&amp;"); //$NON-NLS-1$
×
174
    }
×
175

176
    private void handleGreaterThan() {
177
        printWriter.print("&gt;"); //$NON-NLS-1$
×
178
    }
×
179

180
    private void handleLessThan() {
181
        printWriter.print("&lt;"); //$NON-NLS-1$
×
182
    }
×
183

184
    /**
185
     * Extracts the XML version from the Document.
186
     *
187
     * @param document
188
     *            the document
189
     * @return the version
190
     */
191
    protected String getVersion(Document document) {
192
        return document.getXmlVersion();
1✔
193
    }
194

195
    protected void writeAnyNode(Node node) throws ShellException {
196
        short type = node.getNodeType();
1✔
197
        switch (type) {
1!
198
        case Node.DOCUMENT_NODE:
199
            write((Document) node);
×
200
            break;
×
201

202
        case Node.DOCUMENT_TYPE_NODE:
203
            write((DocumentType) node);
×
204
            break;
×
205

206
        case Node.ELEMENT_NODE:
207
            write((Element) node);
1✔
208
            break;
1✔
209

210
        case Node.ENTITY_REFERENCE_NODE:
211
            write((EntityReference) node);
×
212
            break;
×
213

214
        case Node.CDATA_SECTION_NODE:
215
            write((CDATASection) node);
1✔
216
            break;
1✔
217

218
        case Node.TEXT_NODE:
219
            write((Text) node);
1✔
220
            break;
1✔
221

222
        case Node.PROCESSING_INSTRUCTION_NODE:
223
            write((ProcessingInstruction) node);
×
224
            break;
×
225

226
        case Node.COMMENT_NODE:
227
            write((Comment) node);
1✔
228
            break;
1✔
229

230
        default:
NEW
231
            throw new ShellException(getString("RuntimeError.18", Short.toString(type))); //$NON-NLS-1$
×
232
        }
233
    }
1✔
234

235
    protected void write(Document node) throws ShellException {
236
        isXML11 = "1.1".equals(getVersion(node)); //$NON-NLS-1$
1✔
237
        if (isXML11) {
1!
238
            printWriter.println("<?xml version=\"1.1\" encoding=\"UTF-8\"?>"); //$NON-NLS-1$
×
239
        } else {
240
            printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); //$NON-NLS-1$
1✔
241
        }
242
        printWriter.flush();
1✔
243
        write(node.getDoctype());
1✔
244
        write(node.getDocumentElement());
1✔
245
    }
1✔
246

247
    protected void write(DocumentType node) {
248
        printWriter.print("<!DOCTYPE "); //$NON-NLS-1$
1✔
249
        printWriter.print(node.getName());
1✔
250
        String publicId = node.getPublicId();
1✔
251
        String systemId = node.getSystemId();
1✔
252
        if (publicId != null) {
1!
253
            printWriter.print(" PUBLIC \""); //$NON-NLS-1$
1✔
254
            printWriter.print(publicId);
1✔
255
            printWriter.print("\" \""); //$NON-NLS-1$
1✔
256
            printWriter.print(systemId);
1✔
257
            printWriter.print('\"');
1✔
258
        } else if (systemId != null) {
×
259
            printWriter.print(" SYSTEM \""); //$NON-NLS-1$
×
260
            printWriter.print(systemId);
×
261
            printWriter.print('"');
×
262
        }
263

264
        String internalSubset = node.getInternalSubset();
1✔
265
        if (internalSubset != null) {
1!
266
            printWriter.println(" ["); //$NON-NLS-1$
×
267
            printWriter.print(internalSubset);
×
268
            printWriter.print(']');
×
269
        }
270
        printWriter.println('>');
1✔
271
    }
1✔
272

273
    protected void write(Element node) throws ShellException {
274
        printWriter.print('<');
1✔
275
        printWriter.print(node.getNodeName());
1✔
276
        Attr[] attrs = sortAttributes(node.getAttributes());
1✔
277
        for (Attr attr : attrs) {
1✔
278
            printWriter.print(' ');
1✔
279
            printWriter.print(attr.getNodeName());
1✔
280
            printWriter.print("=\""); //$NON-NLS-1$
1✔
281
            normalizeAndPrint(attr.getNodeValue(), true);
1✔
282
            printWriter.print('"');
1✔
283
        }
284

285
        if (node.getChildNodes().getLength() == 0) {
1✔
286
            printWriter.print(" />"); //$NON-NLS-1$
1✔
287
            printWriter.flush();
1✔
288
        } else {
289
            printWriter.print('>');
1✔
290
            printWriter.flush();
1✔
291

292
            Node child = node.getFirstChild();
1✔
293
            while (child != null) {
1✔
294
                writeAnyNode(child);
1✔
295
                child = child.getNextSibling();
1✔
296
            }
297

298
            printWriter.print("</"); //$NON-NLS-1$
1✔
299
            printWriter.print(node.getNodeName());
1✔
300
            printWriter.print('>');
1✔
301
            printWriter.flush();
1✔
302
        }
303
    }
1✔
304

305
    protected void write(EntityReference node) {
306
        printWriter.print('&');
×
307
        printWriter.print(node.getNodeName());
×
308
        printWriter.print(';');
×
309
        printWriter.flush();
×
310
    }
×
311

312
    protected void write(CDATASection node) {
313
        printWriter.print("<![CDATA["); //$NON-NLS-1$
1✔
314
        String data = node.getNodeValue();
1✔
315
        // XML parsers normalize line endings to '\n'. We should write
316
        // it out as it was in the original to avoid whitespace commits
317
        // on some version control systems
318
        int len = (data != null) ? data.length() : 0;
1!
319
        for (int i = 0; i < len; i++) {
1✔
320
            char c = data.charAt(i);
1✔
321
            if (c == '\n') {
1✔
322
                handleLineFeed();
1✔
323
            } else {
324
                printWriter.print(c);
1✔
325
            }
326
        }
327
        printWriter.print("]]>"); //$NON-NLS-1$
1✔
328
        printWriter.flush();
1✔
329
    }
1✔
330

331
    protected void write(Text node) {
332
        normalizeAndPrint(node.getNodeValue(), false);
1✔
333
        printWriter.flush();
1✔
334
    }
1✔
335

336
    protected void write(ProcessingInstruction node) {
337
        printWriter.print("<?"); //$NON-NLS-1$
×
338
        printWriter.print(node.getNodeName());
×
339
        String data = node.getNodeValue();
×
340
        if (data != null && !data.isEmpty()) {
×
341
            printWriter.print(' ');
×
342
            printWriter.print(data);
×
343
        }
344
        printWriter.print("?>"); //$NON-NLS-1$
×
345
        printWriter.flush();
×
346
    }
×
347

348
    protected void write(Comment node) {
349
        printWriter.print("<!--"); //$NON-NLS-1$
1✔
350
        String comment = node.getNodeValue();
1✔
351
        if (comment != null && !comment.isEmpty()) {
1!
352
            normalizeAndPrint(comment, false);
1✔
353
        }
354
        printWriter.print("-->"); //$NON-NLS-1$
1✔
355
        printWriter.flush();
1✔
356
    }
1✔
357
}
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