src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/TransducedAccessor.java

Fri, 23 Aug 2013 09:57:21 +0100

author
mkos
date
Fri, 23 Aug 2013 09:57:21 +0100
changeset 397
b99d7e355d4b
parent 286
f50545b5e2f1
child 450
b0c2840e2513
permissions
-rw-r--r--

8022885: Update JAX-WS RI integration to 2.2.9-b14140
8013016: Rebase 8009009 against the latest jdk8/jaxws
Reviewed-by: alanb, chegar

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 package com.sun.xml.internal.bind.v2.runtime.reflect;
ohair@286 27
ohair@286 28 import java.io.IOException;
ohair@286 29 import java.util.concurrent.Callable;
ohair@286 30
ohair@286 31 import javax.xml.bind.JAXBException;
ohair@286 32 import javax.xml.bind.annotation.XmlValue;
ohair@286 33 import javax.xml.stream.XMLStreamException;
ohair@286 34
ohair@286 35 import com.sun.istack.internal.NotNull;
ohair@286 36 import com.sun.istack.internal.Nullable;
ohair@286 37 import com.sun.istack.internal.SAXException2;
ohair@286 38 import com.sun.xml.internal.bind.WhiteSpaceProcessor;
ohair@286 39 import com.sun.xml.internal.bind.api.AccessorException;
ohair@286 40 import com.sun.xml.internal.bind.v2.model.core.ID;
ohair@286 41 import com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder;
ohair@286 42 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
ohair@286 43 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeNonElementRef;
ohair@286 44 import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
ohair@286 45 import com.sun.xml.internal.bind.v2.runtime.Name;
ohair@286 46 import com.sun.xml.internal.bind.v2.runtime.Transducer;
ohair@286 47 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
ohair@286 48 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
ohair@286 49 import com.sun.xml.internal.bind.v2.runtime.reflect.opt.OptimizedTransducedAccessorFactory;
ohair@286 50 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Patcher;
ohair@286 51 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
ohair@286 52 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx;
ohair@286 53
ohair@286 54 import org.xml.sax.SAXException;
ohair@286 55
ohair@286 56 /**
ohair@286 57 * {@link Accessor} and {@link Transducer} combined into one object.
ohair@286 58 *
ohair@286 59 * <p>
ohair@286 60 * This allows efficient conversions between primitive values and
ohair@286 61 * String without using boxing.
ohair@286 62 *
ohair@286 63 * <p>
ohair@286 64 * This abstraction only works for a single-value property.
ohair@286 65 *
ohair@286 66 * <p>
ohair@286 67 * An instance of {@link TransducedAccessor} implicitly holds a
ohair@286 68 * field of the {@code BeanT} that the accessors access.
ohair@286 69 *
ohair@286 70 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
ohair@286 71 */
ohair@286 72 public abstract class TransducedAccessor<BeanT> {
ohair@286 73
ohair@286 74 /**
ohair@286 75 * @see Transducer#useNamespace()
ohair@286 76 */
ohair@286 77 public boolean useNamespace() {
ohair@286 78 return false;
ohair@286 79 }
ohair@286 80
ohair@286 81 /**
ohair@286 82 * Obtain the value of the field and declares the namespace URIs used in
ohair@286 83 * the value.
ohair@286 84 *
ohair@286 85 * @see Transducer#declareNamespace(Object, XMLSerializer)
ohair@286 86 */
ohair@286 87 public void declareNamespace( BeanT o, XMLSerializer w ) throws AccessorException, SAXException {
ohair@286 88 }
ohair@286 89
ohair@286 90 /**
ohair@286 91 * Prints the responsible field of the given bean to the writer.
ohair@286 92 *
ohair@286 93 * <p>
ohair@286 94 * Use {@link XMLSerializer#getInstance()} to access to the namespace bindings
ohair@286 95 *
ohair@286 96 * @return
ohair@286 97 * if the accessor didn't yield a value, return null.
ohair@286 98 */
ohair@286 99 public abstract @Nullable CharSequence print(@NotNull BeanT o) throws AccessorException, SAXException;
ohair@286 100
ohair@286 101 /**
ohair@286 102 * Parses the text value into the responsible field of the given bean.
ohair@286 103 *
ohair@286 104 * <p>
ohair@286 105 * Use {@link UnmarshallingContext#getInstance()} to access to the namespace bindings
ohair@286 106 *
ohair@286 107 * @throws AccessorException
ohair@286 108 * if the transducer is used to parse an user bean that uses {@link XmlValue},
ohair@286 109 * then this exception may occur when it tries to set the leaf value to the bean.
ohair@286 110 * @throws RuntimeException
ohair@286 111 * if the lexical form is incorrect. The method may throw a RuntimeException,
ohair@286 112 * but it shouldn't cause the entire unmarshalling to fail.
ohair@286 113 * @throws SAXException
ohair@286 114 * if the parse method found an error, the error is reported, and then
ohair@286 115 * the processing is aborted.
ohair@286 116 */
ohair@286 117 public abstract void parse(BeanT o, CharSequence lexical) throws AccessorException, SAXException;
ohair@286 118
ohair@286 119 /**
ohair@286 120 * Checks if the field has a value.
ohair@286 121 */
ohair@286 122 public abstract boolean hasValue(BeanT o) throws AccessorException;
ohair@286 123
ohair@286 124
ohair@286 125
ohair@286 126
ohair@286 127
ohair@286 128
ohair@286 129
ohair@286 130
ohair@286 131
ohair@286 132
ohair@286 133
ohair@286 134 /**
ohair@286 135 * Gets the {@link TransducedAccessor} appropriately configured for
ohair@286 136 * the given property.
ohair@286 137 *
ohair@286 138 * <p>
ohair@286 139 * This allows the implementation to use an optimized code.
ohair@286 140 */
ohair@286 141 public static <T> TransducedAccessor<T> get(JAXBContextImpl context, RuntimeNonElementRef ref) {
ohair@286 142 Transducer xducer = RuntimeModelBuilder.createTransducer(ref);
ohair@286 143 RuntimePropertyInfo prop = ref.getSource();
ohair@286 144
ohair@286 145 if(prop.isCollection()) {
ohair@286 146 return new ListTransducedAccessorImpl(xducer,prop.getAccessor(),
ohair@286 147 Lister.create(Navigator.REFLECTION.erasure(prop.getRawType()),prop.id(),
ohair@286 148 prop.getAdapter()));
ohair@286 149 }
ohair@286 150
ohair@286 151 if(prop.id()==ID.IDREF)
ohair@286 152 return new IDREFTransducedAccessorImpl(prop.getAccessor());
ohair@286 153
ohair@286 154 if(xducer.isDefault() && context != null && !context.fastBoot) {
ohair@286 155 TransducedAccessor xa = OptimizedTransducedAccessorFactory.get(prop);
ohair@286 156 if(xa!=null) return xa;
ohair@286 157 }
ohair@286 158
ohair@286 159 if(xducer.useNamespace())
ohair@286 160 return new CompositeContextDependentTransducedAccessorImpl( context, xducer, prop.getAccessor() );
ohair@286 161 else
ohair@286 162 return new CompositeTransducedAccessorImpl( context, xducer, prop.getAccessor() );
ohair@286 163 }
ohair@286 164
ohair@286 165 /**
ohair@286 166 * Convenience method to write the value as a text inside an element
ohair@286 167 * without any attributes.
ohair@286 168 * Can be overridden for improved performance.
ohair@286 169 *
ohair@286 170 * <p>
ohair@286 171 * The callee assumes that there's an associated value in the field.
ohair@286 172 * No @xsi:type handling is expected.
ohair@286 173 */
ohair@286 174 public abstract void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws SAXException, AccessorException, IOException, XMLStreamException;
ohair@286 175
ohair@286 176 /**
ohair@286 177 * Invokes one of the {@link XMLSerializer#text(String, String)} method
ohair@286 178 * with the representation of data bested suited for this transduced accessor.
ohair@286 179 */
ohair@286 180 public abstract void writeText(XMLSerializer w, BeanT o, String fieldName) throws AccessorException, SAXException, IOException, XMLStreamException;
ohair@286 181
ohair@286 182 static class CompositeContextDependentTransducedAccessorImpl<BeanT,ValueT> extends CompositeTransducedAccessorImpl<BeanT,ValueT> {
ohair@286 183 public CompositeContextDependentTransducedAccessorImpl(JAXBContextImpl context,Transducer<ValueT> xducer, Accessor<BeanT,ValueT> acc) {
ohair@286 184 super(context,xducer,acc);
ohair@286 185 assert xducer.useNamespace();
ohair@286 186 }
ohair@286 187
ohair@286 188 @Override
ohair@286 189 public boolean useNamespace() {
ohair@286 190 return true;
ohair@286 191 }
ohair@286 192
ohair@286 193 @Override
ohair@286 194 public void declareNamespace(BeanT bean, XMLSerializer w) throws AccessorException {
ohair@286 195 ValueT o = acc.get(bean);
ohair@286 196 if(o!=null)
ohair@286 197 xducer.declareNamespace(o,w);
ohair@286 198 }
ohair@286 199
ohair@286 200 @Override
ohair@286 201 public void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws SAXException, AccessorException, IOException, XMLStreamException {
ohair@286 202 w.startElement(tagName,null);
ohair@286 203 declareNamespace(o,w);
ohair@286 204 w.endNamespaceDecls(null);
ohair@286 205 w.endAttributes();
ohair@286 206 xducer.writeText(w,acc.get(o),fieldName);
ohair@286 207 w.endElement();
ohair@286 208 }
ohair@286 209 }
ohair@286 210
ohair@286 211
ohair@286 212 /**
ohair@286 213 * Implementation of {@link TransducedAccessor} that
ohair@286 214 * simply combines a {@link Transducer} and {@link Accessor}.
ohair@286 215 */
ohair@286 216 public static class CompositeTransducedAccessorImpl<BeanT,ValueT> extends TransducedAccessor<BeanT> {
ohair@286 217 protected final Transducer<ValueT> xducer;
ohair@286 218 protected final Accessor<BeanT,ValueT> acc;
ohair@286 219
ohair@286 220 public CompositeTransducedAccessorImpl(JAXBContextImpl context, Transducer<ValueT> xducer, Accessor<BeanT,ValueT> acc) {
ohair@286 221 this.xducer = xducer;
ohair@286 222 this.acc = acc.optimize(context);
ohair@286 223 }
ohair@286 224
ohair@286 225 public CharSequence print(BeanT bean) throws AccessorException {
ohair@286 226 ValueT o = acc.get(bean);
ohair@286 227 if(o==null) return null;
ohair@286 228 return xducer.print(o);
ohair@286 229 }
ohair@286 230
ohair@286 231 public void parse(BeanT bean, CharSequence lexical) throws AccessorException, SAXException {
ohair@286 232 acc.set(bean,xducer.parse(lexical));
ohair@286 233 }
ohair@286 234
ohair@286 235 public boolean hasValue(BeanT bean) throws AccessorException {
ohair@286 236 return acc.getUnadapted(bean)!=null;
ohair@286 237 }
ohair@286 238
ohair@286 239 @Override
ohair@286 240 public void writeLeafElement(XMLSerializer w, Name tagName, BeanT o, String fieldName) throws SAXException, AccessorException, IOException, XMLStreamException {
ohair@286 241 xducer.writeLeafElement(w,tagName,acc.get(o),fieldName);
ohair@286 242 }
ohair@286 243
ohair@286 244 @Override
ohair@286 245 public void writeText(XMLSerializer w, BeanT o, String fieldName) throws AccessorException, SAXException, IOException, XMLStreamException {
ohair@286 246 xducer.writeText(w,acc.get(o),fieldName);
ohair@286 247 }
ohair@286 248 }
ohair@286 249
ohair@286 250 /**
ohair@286 251 * {@link TransducedAccessor} for IDREF.
ohair@286 252 *
ohair@286 253 * BeanT: the type of the bean that contains this the IDREF field.
ohair@286 254 * TargetT: the type of the bean pointed by IDREF.
ohair@286 255 */
ohair@286 256 private static final class IDREFTransducedAccessorImpl<BeanT,TargetT> extends DefaultTransducedAccessor<BeanT> {
ohair@286 257 private final Accessor<BeanT,TargetT> acc;
ohair@286 258 /**
ohair@286 259 * The object that an IDREF resolves to should be
ohair@286 260 * assignable to this type.
ohair@286 261 */
ohair@286 262 private final Class<TargetT> targetType;
ohair@286 263
ohair@286 264 public IDREFTransducedAccessorImpl(Accessor<BeanT, TargetT> acc) {
ohair@286 265 this.acc = acc;
ohair@286 266 this.targetType = acc.getValueType();
ohair@286 267 }
ohair@286 268
ohair@286 269 public String print(BeanT bean) throws AccessorException, SAXException {
ohair@286 270 TargetT target = acc.get(bean);
ohair@286 271 if(target==null) return null;
ohair@286 272
ohair@286 273 XMLSerializer w = XMLSerializer.getInstance();
ohair@286 274 try {
ohair@286 275 String id = w.grammar.getBeanInfo(target,true).getId(target,w);
ohair@286 276 if(id==null)
ohair@286 277 w.errorMissingId(target);
ohair@286 278 return id;
ohair@286 279 } catch (JAXBException e) {
ohair@286 280 w.reportError(null,e);
ohair@286 281 return null;
ohair@286 282 }
ohair@286 283 }
ohair@286 284
ohair@286 285 private void assign( BeanT bean, TargetT t, UnmarshallingContext context ) throws AccessorException {
ohair@286 286 if(!targetType.isInstance(t))
ohair@286 287 context.handleError(Messages.UNASSIGNABLE_TYPE.format(targetType,t.getClass()));
ohair@286 288 else
ohair@286 289 acc.set(bean,t);
ohair@286 290 }
ohair@286 291
ohair@286 292 public void parse(final BeanT bean, CharSequence lexical) throws AccessorException, SAXException {
ohair@286 293 final String idref = WhiteSpaceProcessor.trim(lexical).toString();
ohair@286 294 final UnmarshallingContext context = UnmarshallingContext.getInstance();
ohair@286 295
ohair@286 296 final Callable callable = context.getObjectFromId(idref,acc.valueType);
ohair@286 297 if(callable==null) {
ohair@286 298 // the IDResolver decided to abort it now
ohair@286 299 context.errorUnresolvedIDREF(bean,idref,context.getLocator());
ohair@286 300 return;
ohair@286 301 }
ohair@286 302
ohair@286 303 TargetT t;
ohair@286 304 try {
ohair@286 305 t = (TargetT)callable.call();
ohair@286 306 } catch (SAXException e) {// from callable.call
ohair@286 307 throw e;
ohair@286 308 } catch (RuntimeException e) {// from callable.call
ohair@286 309 throw e;
ohair@286 310 } catch (Exception e) {// from callable.call
ohair@286 311 throw new SAXException2(e);
ohair@286 312 }
ohair@286 313 if(t!=null) {
ohair@286 314 assign(bean,t,context);
ohair@286 315 } else {
ohair@286 316 // try again later
ohair@286 317 final LocatorEx loc = new LocatorEx.Snapshot(context.getLocator());
ohair@286 318 context.addPatcher(new Patcher() {
ohair@286 319 public void run() throws SAXException {
ohair@286 320 try {
ohair@286 321 TargetT t = (TargetT)callable.call();
ohair@286 322 if(t==null) {
ohair@286 323 context.errorUnresolvedIDREF(bean,idref,loc);
ohair@286 324 } else {
ohair@286 325 assign(bean,t,context);
ohair@286 326 }
ohair@286 327 } catch (AccessorException e) {
ohair@286 328 context.handleError(e);
ohair@286 329 } catch (SAXException e) {// from callable.call
ohair@286 330 throw e;
ohair@286 331 } catch (RuntimeException e) {// from callable.call
ohair@286 332 throw e;
ohair@286 333 } catch (Exception e) {// from callable.call
ohair@286 334 throw new SAXException2(e);
ohair@286 335 }
ohair@286 336 }
ohair@286 337 });
ohair@286 338 }
ohair@286 339 }
ohair@286 340
ohair@286 341 public boolean hasValue(BeanT bean) throws AccessorException {
ohair@286 342 return acc.get(bean)!=null;
ohair@286 343 }
ohair@286 344 }
ohair@286 345 }

mercurial