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

     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 }

mercurial