Fri, 23 Aug 2013 09:57:21 +0100
8022885: Update JAX-WS RI integration to 2.2.9-b14140
8013016: Rebase 8009009 against the latest jdk8/jaxws
Reviewed-by: alanb, chegar
1 /*
2 * Copyright (c) 1997, 2011, 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.reflect;
28 import java.io.IOException;
29 import java.util.concurrent.Callable;
31 import javax.xml.bind.JAXBException;
32 import javax.xml.bind.annotation.XmlValue;
33 import javax.xml.stream.XMLStreamException;
35 import com.sun.istack.internal.NotNull;
36 import com.sun.istack.internal.Nullable;
37 import com.sun.istack.internal.SAXException2;
38 import com.sun.xml.internal.bind.WhiteSpaceProcessor;
39 import com.sun.xml.internal.bind.api.AccessorException;
40 import com.sun.xml.internal.bind.v2.model.core.ID;
41 import com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder;
42 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
43 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeNonElementRef;
44 import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
45 import com.sun.xml.internal.bind.v2.runtime.Name;
46 import com.sun.xml.internal.bind.v2.runtime.Transducer;
47 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
48 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
49 import com.sun.xml.internal.bind.v2.runtime.reflect.opt.OptimizedTransducedAccessorFactory;
50 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Patcher;
51 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
52 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx;
54 import org.xml.sax.SAXException;
56 /**
57 * {@link Accessor} and {@link Transducer} combined into one object.
58 *
59 * <p>
60 * This allows efficient conversions between primitive values and
61 * String without using boxing.
62 *
63 * <p>
64 * This abstraction only works for a single-value property.
65 *
66 * <p>
67 * An instance of {@link TransducedAccessor} implicitly holds a
68 * field of the {@code BeanT} that the accessors access.
69 *
70 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
71 */
72 public abstract class TransducedAccessor<BeanT> {
74 /**
75 * @see Transducer#useNamespace()
76 */
77 public boolean useNamespace() {
78 return false;
79 }
81 /**
82 * Obtain the value of the field and declares the namespace URIs used in
83 * the value.
84 *
85 * @see Transducer#declareNamespace(Object, XMLSerializer)
86 */
87 public void declareNamespace( BeanT o, XMLSerializer w ) throws AccessorException, SAXException {
88 }
90 /**
91 * Prints the responsible field of the given bean to the writer.
92 *
93 * <p>
94 * Use {@link XMLSerializer#getInstance()} to access to the namespace bindings
95 *
96 * @return
97 * if the accessor didn't yield a value, return null.
98 */
99 public abstract @Nullable CharSequence print(@NotNull BeanT o) throws AccessorException, SAXException;
101 /**
102 * Parses the text value into the responsible field of the given bean.
103 *
104 * <p>
105 * Use {@link UnmarshallingContext#getInstance()} to access to the namespace bindings
106 *
107 * @throws AccessorException
108 * if the transducer is used to parse an user bean that uses {@link XmlValue},
109 * then this exception may occur when it tries to set the leaf value to the bean.
110 * @throws RuntimeException
111 * if the lexical form is incorrect. The method may throw a RuntimeException,
112 * but it shouldn't cause the entire unmarshalling to fail.
113 * @throws SAXException
114 * if the parse method found an error, the error is reported, and then
115 * the processing is aborted.
116 */
117 public abstract void parse(BeanT o, CharSequence lexical) throws AccessorException, SAXException;
119 /**
120 * Checks if the field has a value.
121 */
122 public abstract boolean hasValue(BeanT o) throws AccessorException;
134 /**
135 * Gets the {@link TransducedAccessor} appropriately configured for
136 * the given property.
137 *
138 * <p>
139 * This allows the implementation to use an optimized code.
140 */
141 public static <T> TransducedAccessor<T> get(JAXBContextImpl context, RuntimeNonElementRef ref) {
142 Transducer xducer = RuntimeModelBuilder.createTransducer(ref);
143 RuntimePropertyInfo prop = ref.getSource();
145 if(prop.isCollection()) {
146 return new ListTransducedAccessorImpl(xducer,prop.getAccessor(),
147 Lister.create(Navigator.REFLECTION.erasure(prop.getRawType()),prop.id(),
148 prop.getAdapter()));
149 }
151 if(prop.id()==ID.IDREF)
152 return new IDREFTransducedAccessorImpl(prop.getAccessor());
154 if(xducer.isDefault() && context != null && !context.fastBoot) {
155 TransducedAccessor xa = OptimizedTransducedAccessorFactory.get(prop);
156 if(xa!=null) return xa;
157 }
159 if(xducer.useNamespace())
160 return new CompositeContextDependentTransducedAccessorImpl( context, xducer, prop.getAccessor() );
161 else
162 return new CompositeTransducedAccessorImpl( context, xducer, prop.getAccessor() );
163 }
165 /**
166 * Convenience method to write the value as a text inside an element
167 * without any attributes.
168 * Can be overridden for improved performance.
169 *
170 * <p>
171 * The callee assumes that there's an associated value in the field.
172 * No @xsi:type handling is expected.
173 */
174 public abstract void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws SAXException, AccessorException, IOException, XMLStreamException;
176 /**
177 * Invokes one of the {@link XMLSerializer#text(String, String)} method
178 * with the representation of data bested suited for this transduced accessor.
179 */
180 public abstract void writeText(XMLSerializer w, BeanT o, String fieldName) throws AccessorException, SAXException, IOException, XMLStreamException;
182 static class CompositeContextDependentTransducedAccessorImpl<BeanT,ValueT> extends CompositeTransducedAccessorImpl<BeanT,ValueT> {
183 public CompositeContextDependentTransducedAccessorImpl(JAXBContextImpl context,Transducer<ValueT> xducer, Accessor<BeanT,ValueT> acc) {
184 super(context,xducer,acc);
185 assert xducer.useNamespace();
186 }
188 @Override
189 public boolean useNamespace() {
190 return true;
191 }
193 @Override
194 public void declareNamespace(BeanT bean, XMLSerializer w) throws AccessorException {
195 ValueT o = acc.get(bean);
196 if(o!=null)
197 xducer.declareNamespace(o,w);
198 }
200 @Override
201 public void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws SAXException, AccessorException, IOException, XMLStreamException {
202 w.startElement(tagName,null);
203 declareNamespace(o,w);
204 w.endNamespaceDecls(null);
205 w.endAttributes();
206 xducer.writeText(w,acc.get(o),fieldName);
207 w.endElement();
208 }
209 }
212 /**
213 * Implementation of {@link TransducedAccessor} that
214 * simply combines a {@link Transducer} and {@link Accessor}.
215 */
216 public static class CompositeTransducedAccessorImpl<BeanT,ValueT> extends TransducedAccessor<BeanT> {
217 protected final Transducer<ValueT> xducer;
218 protected final Accessor<BeanT,ValueT> acc;
220 public CompositeTransducedAccessorImpl(JAXBContextImpl context, Transducer<ValueT> xducer, Accessor<BeanT,ValueT> acc) {
221 this.xducer = xducer;
222 this.acc = acc.optimize(context);
223 }
225 public CharSequence print(BeanT bean) throws AccessorException {
226 ValueT o = acc.get(bean);
227 if(o==null) return null;
228 return xducer.print(o);
229 }
231 public void parse(BeanT bean, CharSequence lexical) throws AccessorException, SAXException {
232 acc.set(bean,xducer.parse(lexical));
233 }
235 public boolean hasValue(BeanT bean) throws AccessorException {
236 return acc.getUnadapted(bean)!=null;
237 }
239 @Override
240 public void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws SAXException, AccessorException, IOException, XMLStreamException {
241 xducer.writeLeafElement(w,tagName,acc.get(o),fieldName);
242 }
244 @Override
245 public void writeText(XMLSerializer w, BeanT o, String fieldName) throws AccessorException, SAXException, IOException, XMLStreamException {
246 xducer.writeText(w,acc.get(o),fieldName);
247 }
248 }
250 /**
251 * {@link TransducedAccessor} for IDREF.
252 *
253 * BeanT: the type of the bean that contains this the IDREF field.
254 * TargetT: the type of the bean pointed by IDREF.
255 */
256 private static final class IDREFTransducedAccessorImpl<BeanT,TargetT> extends DefaultTransducedAccessor<BeanT> {
257 private final Accessor<BeanT,TargetT> acc;
258 /**
259 * The object that an IDREF resolves to should be
260 * assignable to this type.
261 */
262 private final Class<TargetT> targetType;
264 public IDREFTransducedAccessorImpl(Accessor<BeanT, TargetT> acc) {
265 this.acc = acc;
266 this.targetType = acc.getValueType();
267 }
269 public String print(BeanT bean) throws AccessorException, SAXException {
270 TargetT target = acc.get(bean);
271 if(target==null) return null;
273 XMLSerializer w = XMLSerializer.getInstance();
274 try {
275 String id = w.grammar.getBeanInfo(target,true).getId(target,w);
276 if(id==null)
277 w.errorMissingId(target);
278 return id;
279 } catch (JAXBException e) {
280 w.reportError(null,e);
281 return null;
282 }
283 }
285 private void assign( BeanT bean, TargetT t, UnmarshallingContext context ) throws AccessorException {
286 if(!targetType.isInstance(t))
287 context.handleError(Messages.UNASSIGNABLE_TYPE.format(targetType,t.getClass()));
288 else
289 acc.set(bean,t);
290 }
292 public void parse(final BeanT bean, CharSequence lexical) throws AccessorException, SAXException {
293 final String idref = WhiteSpaceProcessor.trim(lexical).toString();
294 final UnmarshallingContext context = UnmarshallingContext.getInstance();
296 final Callable callable = context.getObjectFromId(idref,acc.valueType);
297 if(callable==null) {
298 // the IDResolver decided to abort it now
299 context.errorUnresolvedIDREF(bean,idref,context.getLocator());
300 return;
301 }
303 TargetT t;
304 try {
305 t = (TargetT)callable.call();
306 } catch (SAXException e) {// from callable.call
307 throw e;
308 } catch (RuntimeException e) {// from callable.call
309 throw e;
310 } catch (Exception e) {// from callable.call
311 throw new SAXException2(e);
312 }
313 if(t!=null) {
314 assign(bean,t,context);
315 } else {
316 // try again later
317 final LocatorEx loc = new LocatorEx.Snapshot(context.getLocator());
318 context.addPatcher(new Patcher() {
319 public void run() throws SAXException {
320 try {
321 TargetT t = (TargetT)callable.call();
322 if(t==null) {
323 context.errorUnresolvedIDREF(bean,idref,loc);
324 } else {
325 assign(bean,t,context);
326 }
327 } catch (AccessorException e) {
328 context.handleError(e);
329 } catch (SAXException e) {// from callable.call
330 throw e;
331 } catch (RuntimeException e) {// from callable.call
332 throw e;
333 } catch (Exception e) {// from callable.call
334 throw new SAXException2(e);
335 }
336 }
337 });
338 }
339 }
341 public boolean hasValue(BeanT bean) throws AccessorException {
342 return acc.get(bean)!=null;
343 }
344 }
345 }