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

Sun, 31 Aug 2014 16:14:36 +0400

author
aefimov
date
Sun, 31 Aug 2014 16:14:36 +0400
changeset 650
121e938cb9c3
parent 450
b0c2840e2513
child 637
9c07ef4934dd
permissions
-rw-r--r--

8036981: JAXB not preserving formatting for xsd:any Mixed content
Reviewed-by: lancea, mkos

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

mercurial