Sun, 31 Aug 2014 16:14:36 +0400
8036981: JAXB not preserving formatting for xsd:any Mixed content
Reviewed-by: lancea, mkos
1 /*
2 * Copyright (c) 1997, 2014, 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.bind.v2.runtime.unmarshaller;
28 import com.sun.xml.internal.bind.Util;
29 import javax.xml.bind.JAXBException;
30 import javax.xml.bind.UnmarshallerHandler;
32 import com.sun.xml.internal.bind.WhiteSpaceProcessor;
33 import com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
37 import org.xml.sax.Attributes;
38 import org.xml.sax.Locator;
39 import org.xml.sax.SAXException;
41 /**
42 * Receives SAX events and convert them to our internal events.
43 *
44 * @author Kohsuke Kawaguchi
45 */
46 public final class SAXConnector implements UnmarshallerHandler {
48 private LocatorEx loc;
50 private static final Logger logger = Util.getClassLogger();
52 /**
53 * SAX may fire consecutive characters event, but we don't allow it.
54 * so use this buffer to perform buffering.
55 */
56 private final StringBuilder buffer = new StringBuilder();
58 private final XmlVisitor next;
59 private final UnmarshallingContext context;
60 private final XmlVisitor.TextPredictor predictor;
62 private static final class TagNameImpl extends TagName {
63 String qname;
64 @Override
65 public String getQname() {
66 return qname;
67 }
68 }
70 private final TagNameImpl tagName = new TagNameImpl();
72 /**
73 * @param externalLocator
74 * If the caller is producing SAX events from sources other than Unicode and angle brackets,
75 * the caller can override the default SAX {@link Locator} object by this object
76 * to provide better location information.
77 */
78 public SAXConnector(XmlVisitor next, LocatorEx externalLocator ) {
79 this.next = next;
80 this.context = next.getContext();
81 this.predictor = next.getPredictor();
82 this.loc = externalLocator;
83 }
85 @Override
86 public Object getResult() throws JAXBException, IllegalStateException {
87 return context.getResult();
88 }
90 public UnmarshallingContext getContext() {
91 return context;
92 }
94 @Override
95 public void setDocumentLocator(final Locator locator) {
96 if(loc!=null)
97 return; // we already have an external locator. ignore.
99 this.loc = new LocatorExWrapper(locator);
100 }
102 @Override
103 public void startDocument() throws SAXException {
104 if (logger.isLoggable(Level.FINER)) {
105 logger.log(Level.FINER, "SAXConnector.startDocument");
106 }
107 next.startDocument(loc,null);
108 }
110 @Override
111 public void endDocument() throws SAXException {
112 if (logger.isLoggable(Level.FINER)) {
113 logger.log(Level.FINER, "SAXConnector.endDocument");
114 }
115 next.endDocument();
116 }
118 @Override
119 public void startPrefixMapping(String prefix, String uri) throws SAXException {
120 if (logger.isLoggable(Level.FINER)) {
121 logger.log(Level.FINER, "SAXConnector.startPrefixMapping: {0}:{1}", new Object[]{prefix, uri});
122 }
123 next.startPrefixMapping(prefix,uri);
124 }
126 @Override
127 public void endPrefixMapping(String prefix) throws SAXException {
128 if (logger.isLoggable(Level.FINER)) {
129 logger.log(Level.FINER, "SAXConnector.endPrefixMapping: {0}", new Object[]{prefix});
130 }
131 next.endPrefixMapping(prefix);
132 }
134 @Override
135 public void startElement(String uri, String local, String qname, Attributes atts) throws SAXException {
136 if (logger.isLoggable(Level.FINER)) {
137 logger.log(Level.FINER, "SAXConnector.startElement: {0}:{1}:{2}, attrs: {3}", new Object[]{uri, local, qname, atts});
138 }
139 // work gracefully with misconfigured parsers that don't support namespaces
140 if( uri==null || uri.length()==0 )
141 uri="";
142 if( local==null || local.length()==0 )
143 local=qname;
144 if( qname==null || qname.length()==0 )
145 qname=local;
147 processText(!context.getCurrentState().isMixed());
149 tagName.uri = uri;
150 tagName.local = local;
151 tagName.qname = qname;
152 tagName.atts = atts;
153 next.startElement(tagName);
154 }
156 @Override
157 public void endElement(String uri, String localName, String qName) throws SAXException {
158 if (logger.isLoggable(Level.FINER)) {
159 logger.log(Level.FINER, "SAXConnector.startElement: {0}:{1}:{2}", new Object[]{uri, localName, qName});
160 }
161 processText(false);
162 tagName.uri = uri;
163 tagName.local = localName;
164 tagName.qname = qName;
165 next.endElement(tagName);
166 }
169 @Override
170 public final void characters( char[] buf, int start, int len ) {
171 if (logger.isLoggable(Level.FINEST)) {
172 logger.log(Level.FINEST, "SAXConnector.characters: {0}", buf);
173 }
174 if( predictor.expectText() )
175 buffer.append(buf,start,len);
176 }
178 @Override
179 public final void ignorableWhitespace( char[] buf, int start, int len ) {
180 if (logger.isLoggable(Level.FINEST)) {
181 logger.log(Level.FINEST, "SAXConnector.characters{0}", buf);
182 }
183 characters(buf,start,len);
184 }
186 @Override
187 public void processingInstruction(String target, String data) {
188 // nop
189 }
191 @Override
192 public void skippedEntity(String name) {
193 // nop
194 }
196 private void processText( boolean ignorable ) throws SAXException {
197 if (predictor.expectText() && (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer)))
198 next.text(buffer);
199 buffer.setLength(0);
200 }
202 }