Sun, 18 Jun 2017 23:18:45 +0100
8172297: In java 8, the marshalling with JAX-WS does not escape carriage return
Reviewed-by: lancea
1 /*
2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.txw2.output;
28 import org.w3c.dom.Document;
29 import org.w3c.dom.Element;
30 import org.w3c.dom.Node;
31 import org.w3c.dom.Text;
32 import org.xml.sax.Attributes;
33 import org.xml.sax.ContentHandler;
34 import org.xml.sax.Locator;
35 import org.xml.sax.SAXException;
36 import org.xml.sax.ext.LexicalHandler;
38 import javax.xml.parsers.DocumentBuilder;
39 import javax.xml.parsers.DocumentBuilderFactory;
40 import javax.xml.parsers.ParserConfigurationException;
41 import javax.xml.transform.dom.DOMResult;
42 import java.util.ArrayList;
43 import java.util.Stack;
45 import com.sun.xml.internal.txw2.TxwException;
47 /**
48 * {@link XmlSerializer} for {@link javax.xml.transform.dom.DOMResult} and {@link org.w3c.dom.Node}.
49 *
50 * @author Ryan.Shoemaker@Sun.COM
51 */
52 public class DomSerializer implements XmlSerializer {
54 // delegate to SaxSerializer
55 private final SaxSerializer serializer;
57 public DomSerializer(Node node) {
58 Dom2SaxAdapter adapter = new Dom2SaxAdapter(node);
59 serializer = new SaxSerializer(adapter,adapter,false);
60 }
62 public DomSerializer(DOMResult domResult) {
63 Node node = domResult.getNode();
65 if (node == null) {
66 try {
67 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
68 dbf.setNamespaceAware(true);
69 DocumentBuilder db = dbf.newDocumentBuilder();
70 Document doc = db.newDocument();
71 domResult.setNode(doc);
72 serializer = new SaxSerializer(new Dom2SaxAdapter(doc),null,false);
73 } catch (ParserConfigurationException pce) {
74 throw new TxwException(pce);
75 }
76 } else {
77 serializer = new SaxSerializer(new Dom2SaxAdapter(node),null,false);
78 }
79 }
81 // XmlSerializer api's - delegate to SaxSerializer
82 public void startDocument() {
83 serializer.startDocument();
84 }
86 public void beginStartTag(String uri, String localName, String prefix) {
87 serializer.beginStartTag(uri, localName, prefix);
88 }
90 public void writeAttribute(String uri, String localName, String prefix, StringBuilder value) {
91 serializer.writeAttribute(uri, localName, prefix, value);
92 }
94 public void writeXmlns(String prefix, String uri) {
95 serializer.writeXmlns(prefix, uri);
96 }
98 public void endStartTag(String uri, String localName, String prefix) {
99 serializer.endStartTag(uri, localName, prefix);
100 }
102 public void endTag() {
103 serializer.endTag();
104 }
106 public void text(StringBuilder text) {
107 serializer.text(text);
108 }
110 public void cdata(StringBuilder text) {
111 serializer.cdata(text);
112 }
114 public void comment(StringBuilder comment) {
115 serializer.comment(comment);
116 }
118 public void endDocument() {
119 serializer.endDocument();
120 }
122 public void flush() {
123 // no flushing
124 }
125 }
130 /**
131 * Builds a DOM tree from SAX2 events.
132 *
133 * @author Vivek Pandey
134 */
135 class Dom2SaxAdapter implements ContentHandler, LexicalHandler {
137 private final Node _node;
138 private final Stack _nodeStk = new Stack();
139 private boolean inCDATA;
141 public final Element getCurrentElement() {
142 return (Element) _nodeStk.peek();
143 }
145 /**
146 * Document object that owns the specified node.
147 */
148 private final Document _document;
150 /**
151 * @param node
152 * Nodes will be created and added under this object.
153 */
154 public Dom2SaxAdapter(Node node)
155 {
156 _node = node;
157 _nodeStk.push(_node);
159 if( node instanceof Document )
160 this._document = (Document)node;
161 else
162 this._document = node.getOwnerDocument();
163 }
165 /**
166 * Creates a fresh empty DOM document and adds nodes under this document.
167 */
168 public Dom2SaxAdapter() throws ParserConfigurationException {
169 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
170 factory.setNamespaceAware(true);
171 factory.setValidating(false);
173 _document = factory.newDocumentBuilder().newDocument();
174 _node = _document;
175 _nodeStk.push( _document );
176 }
178 public Node getDOM() {
179 return _node;
180 }
182 public void startDocument() {
183 }
185 public void endDocument(){
186 }
188 public void startElement(String namespace, String localName, String qName, Attributes attrs){
190 // some broken DOM implementatino (we confirmed it with SAXON)
191 // return null from this method.
192 Element element = _document.createElementNS(namespace, qName);
194 if( element==null ) {
195 // if so, report an user-friendly error message,
196 // rather than dying mysteriously with NPE.
197 throw new TxwException("Your DOM provider doesn't support the createElementNS method properly");
198 }
200 // process namespace bindings
201 for( int i=0; i<unprocessedNamespaces.size(); i+=2 ) {
202 String prefix = (String)unprocessedNamespaces.get(i+0);
203 String uri = (String)unprocessedNamespaces.get(i+1);
205 String qname;
206 if( "".equals(prefix) || prefix==null )
207 qname = "xmlns";
208 else
209 qname = "xmlns:"+prefix;
211 // older version of Xerces (I confirmed that the bug is gone with Xerces 2.4.0)
212 // have a problem of re-setting the same namespace attribute twice.
213 // work around this bug removing it first.
214 if( element.hasAttributeNS("http://www.w3.org/2000/xmlns/",qname) ) {
215 // further workaround for an old Crimson bug where the removeAttribtueNS
216 // method throws NPE when the element doesn't have any attribute.
217 // to be on the safe side, check the existence of attributes before
218 // attempting to remove it.
219 // for details about this bug, see org.apache.crimson.tree.ElementNode2
220 // line 540 or the following message:
221 // https://jaxb.dev.java.net/servlets/ReadMsg?list=users&msgNo=2767
222 element.removeAttributeNS("http://www.w3.org/2000/xmlns/",qname);
223 }
224 // workaround until here
226 element.setAttributeNS("http://www.w3.org/2000/xmlns/",qname, uri);
227 }
228 unprocessedNamespaces.clear();
231 int length = attrs.getLength();
232 for(int i=0;i<length;i++){
233 String namespaceuri = attrs.getURI(i);
234 String value = attrs.getValue(i);
235 String qname = attrs.getQName(i);
236 element.setAttributeNS(namespaceuri, qname, value);
237 }
238 // append this new node onto current stack node
239 getParent().appendChild(element);
240 // push this node onto stack
241 _nodeStk.push(element);
242 }
244 private final Node getParent() {
245 return (Node) _nodeStk.peek();
246 }
248 public void endElement(String namespace, String localName, String qName){
249 _nodeStk.pop();
250 }
253 public void characters(char[] ch, int start, int length) {
254 Node text;
255 if(inCDATA)
256 text = _document.createCDATASection(new String(ch, start, length));
257 else
258 text = _document.createTextNode(new String(ch, start, length));
259 getParent().appendChild(text);
260 }
262 public void comment(char ch[], int start, int length) throws SAXException {
263 getParent().appendChild(_document.createComment(new String(ch,start,length)));
264 }
268 public void ignorableWhitespace(char[] ch, int start, int length) {
269 }
271 public void processingInstruction(String target, String data) throws org.xml.sax.SAXException{
272 Node node = _document.createProcessingInstruction(target, data);
273 getParent().appendChild(node);
274 }
276 public void setDocumentLocator(Locator locator) {
277 }
279 public void skippedEntity(String name) {
280 }
282 private ArrayList unprocessedNamespaces = new ArrayList();
284 public void startPrefixMapping(String prefix, String uri) {
285 unprocessedNamespaces.add(prefix);
286 unprocessedNamespaces.add(uri);
287 }
289 public void endPrefixMapping(String prefix) {
290 }
292 public void startDTD(String name, String publicId, String systemId) throws SAXException {
293 }
295 public void endDTD() throws SAXException {
296 }
298 public void startEntity(String name) throws SAXException {
299 }
301 public void endEntity(String name) throws SAXException {
302 }
304 public void startCDATA() throws SAXException {
305 inCDATA = true;
306 }
308 public void endCDATA() throws SAXException {
309 inCDATA = false;
310 }
311 }