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

mybatis / generator / 1666

24 May 2025 05:59PM UTC coverage: 88.307% (-0.02%) from 88.328%
1666

push

github

web-flow
Merge pull request #1312 from hazendaz/master

Use NIO classes to resolve modernizer issues

2518 of 3410 branches covered (73.84%)

0 of 44 new or added lines in 7 files covered. (0.0%)

3 existing lines in 2 files now uncovered.

11192 of 12674 relevant lines covered (88.31%)

0.88 hits per line

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

90.12
/core/mybatis-generator-core/src/main/java/org/mybatis/generator/internal/XmlFileMergerJaxp.java
1
/*
2
 *    Copyright 2006-2025 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.File;
21
import java.io.IOException;
22
import java.io.InputStreamReader;
23
import java.io.StringReader;
24
import java.nio.charset.StandardCharsets;
25
import java.nio.file.Files;
26
import java.util.ArrayList;
27
import java.util.List;
28
import javax.xml.XMLConstants;
29
import javax.xml.parsers.DocumentBuilder;
30
import javax.xml.parsers.DocumentBuilderFactory;
31
import javax.xml.parsers.ParserConfigurationException;
32

33
import org.mybatis.generator.api.GeneratedXmlFile;
34
import org.mybatis.generator.config.MergeConstants;
35
import org.mybatis.generator.exception.ShellException;
36
import org.w3c.dom.Comment;
37
import org.w3c.dom.Document;
38
import org.w3c.dom.DocumentType;
39
import org.w3c.dom.Element;
40
import org.w3c.dom.NamedNodeMap;
41
import org.w3c.dom.Node;
42
import org.w3c.dom.NodeList;
43
import org.w3c.dom.Text;
44
import org.xml.sax.EntityResolver;
45
import org.xml.sax.InputSource;
46
import org.xml.sax.SAXException;
47

48
/**
49
 * This class handles the task of merging changes into an existing XML file.
50
 *
51
 * @author Jeff Butler
52
 */
53
public class XmlFileMergerJaxp {
54
    private XmlFileMergerJaxp() {
55
    }
56

57
    private static class NullEntityResolver implements EntityResolver {
58
        /**
59
         * returns an empty reader. This is done so that the parser doesn't
60
         * attempt to read a DTD. We don't need that support for the merge, and
61
         * it can cause problems on systems that aren't Internet connected.
62
         */
63
        @Override
64
        public InputSource resolveEntity(String publicId, String systemId) {
65

66
            StringReader sr = new StringReader(""); //$NON-NLS-1$
1✔
67

68
            return new InputSource(sr);
1✔
69
        }
70
    }
71

72
    public static String getMergedSource(GeneratedXmlFile generatedXmlFile,
73
            File existingFile) throws ShellException {
74

75
        try {
76
            return getMergedSource(new InputSource(new StringReader(generatedXmlFile.getFormattedContent())),
×
NEW
77
                new InputSource(new InputStreamReader(Files.newInputStream(existingFile.toPath()), StandardCharsets.UTF_8)),
×
78
                existingFile.getName());
×
79
        } catch (IOException | SAXException | ParserConfigurationException e) {
×
80
            throw new ShellException(getString("Warning.13", //$NON-NLS-1$
×
81
                    existingFile.getName()), e);
×
82
        }
83
    }
84

85
    public static String getMergedSource(InputSource newFile,
86
            InputSource existingFile, String existingFileName) throws IOException, SAXException,
87
            ParserConfigurationException, ShellException {
88

89
        DocumentBuilderFactory factory = DocumentBuilderFactory
90
                .newInstance();
1✔
91
        factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
1✔
92
        factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
1✔
93
        factory.setExpandEntityReferences(false);
1✔
94
        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
1✔
95
        DocumentBuilder builder = factory.newDocumentBuilder();
1✔
96
        builder.setEntityResolver(new NullEntityResolver());
1✔
97

98
        Document existingDocument = builder.parse(existingFile);
1✔
99
        Document newDocument = builder.parse(newFile);
1✔
100

101
        DocumentType newDocType = newDocument.getDoctype();
1✔
102
        DocumentType existingDocType = existingDocument.getDoctype();
1✔
103

104
        if (!newDocType.getName().equals(existingDocType.getName())) {
1!
105
            throw new ShellException(getString("Warning.12", //$NON-NLS-1$
×
106
                    existingFileName));
107
        }
108

109
        Element existingRootElement = existingDocument.getDocumentElement();
1✔
110
        Element newRootElement = newDocument.getDocumentElement();
1✔
111

112
        // reconcile the root element attributes -
113
        // take all attributes from the new element and add to the existing
114
        // element
115

116
        // remove all attributes from the existing root element
117
        NamedNodeMap attributes = existingRootElement.getAttributes();
1✔
118
        int attributeCount = attributes.getLength();
1✔
119
        for (int i = attributeCount - 1; i >= 0; i--) {
1✔
120
            Node node = attributes.item(i);
1✔
121
            existingRootElement.removeAttribute(node.getNodeName());
1✔
122
        }
123

124
        // add attributes from the new root node to the old root node
125
        attributes = newRootElement.getAttributes();
1✔
126
        attributeCount = attributes.getLength();
1✔
127
        for (int i = 0; i < attributeCount; i++) {
1✔
128
            Node node = attributes.item(i);
1✔
129
            existingRootElement.setAttribute(node.getNodeName(), node
1✔
130
                    .getNodeValue());
1✔
131
        }
132

133
        // remove the old generated elements and any
134
        // white space before the old nodes
135
        List<Node> nodesToDelete = new ArrayList<>();
1✔
136
        NodeList children = existingRootElement.getChildNodes();
1✔
137
        int length = children.getLength();
1✔
138
        for (int i = 0; i < length; i++) {
1✔
139
            Node node = children.item(i);
1✔
140
            if (isGeneratedNode(node)) {
1✔
141
                nodesToDelete.add(node);
1✔
142
            } else if (isWhiteSpace(node)
1✔
143
                    && isGeneratedNode(children.item(i + 1))) {
1✔
144
                nodesToDelete.add(node);
1✔
145
            }
146
        }
147

148
        for (Node node : nodesToDelete) {
1✔
149
            existingRootElement.removeChild(node);
1✔
150
        }
1✔
151

152
        // add the new generated elements
153
        children = newRootElement.getChildNodes();
1✔
154
        length = children.getLength();
1✔
155
        Node firstChild = existingRootElement.getFirstChild();
1✔
156
        for (int i = 0; i < length; i++) {
1!
157
            Node node = children.item(i);
1✔
158
            // don't add the last node if it is only white space
159
            if (i == length - 1 && isWhiteSpace(node)) {
1!
160
                break;
1✔
161
            }
162

163
            Node newNode = existingDocument.importNode(node, true);
1✔
164
            if (firstChild == null) {
1!
165
                existingRootElement.appendChild(newNode);
×
166
            } else {
167
                existingRootElement.insertBefore(newNode, firstChild);
1✔
168
            }
169
        }
170

171
        // pretty print the result
172
        return prettyPrint(existingDocument);
1✔
173
    }
174

175
    private static String prettyPrint(Document document) throws ShellException {
176
        DomWriter dw = new DomWriter();
1✔
177
        return dw.toString(document);
1✔
178
    }
179

180
    private static boolean isGeneratedNode(Node node) {
181
        return node != null
1✔
182
                && node.getNodeType() == Node.ELEMENT_NODE
1✔
183
                && (isOldFormatNode(node) || isNewFormatNode(node));
1✔
184
    }
185

186
    private static boolean isOldFormatNode(Node node) {
187
        Element element = (Element) node;
1✔
188
        String id = element.getAttribute("id"); //$NON-NLS-1$
1✔
189
        return MergeConstants.idStartsWithPrefix(id);
1✔
190

191
    }
192

193
    private static boolean isNewFormatNode(Node node) {
194
        // check for new node format - if the first non-whitespace node
195
        // is an XML comment, and the comment includes
196
        // one of the old element tags,
197
        // then it is a generated node
198
        NodeList children = node.getChildNodes();
1✔
199
        int length = children.getLength();
1✔
200
        for (int i = 0; i < length; i++) {
1✔
201
            Node childNode = children.item(i);
1✔
202
            if (childNode != null && childNode.getNodeType() == Node.COMMENT_NODE) {
1!
203
                String commentData = ((Comment) childNode).getData();
1✔
204
                return MergeConstants.commentContainsTag(commentData);
1✔
205
            }
206
        }
207

208
        return false;
1✔
209
    }
210

211
    private static boolean isWhiteSpace(Node node) {
212
        boolean rc = false;
1✔
213

214
        if (node != null && node.getNodeType() == Node.TEXT_NODE) {
1!
215
            Text tn = (Text) node;
1✔
216
            if (tn.getData().trim().isEmpty()) {
1!
217
                rc = true;
1✔
218
            }
219
        }
220

221
        return rc;
1✔
222
    }
223
}
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

© 2025 Coveralls, Inc