1 /*
   2  * Copyright (c) 1997, 2013, 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  */
  25 
  26 package com.sun.xml.internal.bind.v2.runtime;
  27 
  28 import java.io.IOException;
  29 
  30 import javax.xml.bind.ValidationEvent;
  31 import javax.xml.bind.helpers.ValidationEventImpl;
  32 import javax.xml.namespace.QName;
  33 import javax.xml.stream.XMLStreamException;
  34 
  35 import com.sun.xml.internal.bind.api.AccessorException;
  36 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeLeafInfo;
  37 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
  38 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.TextLoader;
  39 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
  40 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader;
  41 
  42 import org.xml.sax.SAXException;
  43 
  44 /**
  45  * {@link JaxBeanInfo} implementation for immutable leaf classes.
  46  *
  47  * <p>
  48  * Leaf classes are always bound to a text and they are often immutable.
  49  * The JAXB spec allows this binding for a few special Java classes plus
  50  * type-safe enums.
  51  *
  52  * <p>
  53  * This implementation obtains necessary information from {@link RuntimeLeafInfo}.
  54  *
  55  * @author Kohsuke Kawaguchi
  56  */
  57 final class LeafBeanInfoImpl<BeanT> extends JaxBeanInfo<BeanT> {
  58 
  59     private final Loader loader;
  60     private final Loader loaderWithSubst;
  61 
  62     private final Transducer<BeanT> xducer;
  63 
  64     /**
  65      * Non-null only if the leaf is also an element.
  66      */
  67     private final Name tagName;
  68 
  69     public LeafBeanInfoImpl(JAXBContextImpl grammar, RuntimeLeafInfo li) {
  70         super(grammar,li,li.getClazz(),li.getTypeNames(),li.isElement(),true,false);
  71 
  72         xducer = li.getTransducer();
  73         loader = new TextLoader(xducer);
  74         loaderWithSubst = new XsiTypeLoader(this);
  75 
  76         if(isElement())
  77             tagName = grammar.nameBuilder.createElementName(li.getElementName());
  78         else
  79             tagName = null;
  80     }
  81 
  82     @Override
  83     public QName getTypeName(BeanT instance) {
  84         QName tn = xducer.getTypeName(instance);
  85         if(tn!=null)    return tn;
  86         // rely on default
  87         return super.getTypeName(instance);
  88     }
  89 
  90     public final String getElementNamespaceURI(BeanT t) {
  91         return tagName.nsUri;
  92     }
  93 
  94     public final String getElementLocalName(BeanT t) {
  95         return tagName.localName;
  96     }
  97 
  98     public BeanT createInstance(UnmarshallingContext context) {
  99         throw new UnsupportedOperationException();
 100     }
 101 
 102     public final boolean reset(BeanT bean, UnmarshallingContext context) {
 103         return false;
 104     }
 105 
 106     public final String getId(BeanT bean, XMLSerializer target) {
 107         return null;
 108     }
 109 
 110     public final void serializeBody(BeanT bean, XMLSerializer w) throws SAXException, IOException, XMLStreamException {
 111         // most of the times leaves are printed as leaf element/attribute property,
 112         // so this code is only used for example when you have multiple XmlElement on a property
 113         // and some of them are leaves. Hence this doesn't need to be super-fast.
 114         try {
 115             xducer.writeText(w,bean,null);
 116         } catch (AccessorException e) {
 117             w.reportError(null,e);
 118         }
 119     }
 120 
 121     public final void serializeAttributes(BeanT bean, XMLSerializer target) {
 122         // noop
 123     }
 124 
 125     public final void serializeRoot(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
 126         if(tagName==null) {
 127             target.reportError(
 128                 new ValidationEventImpl(
 129                     ValidationEvent.ERROR,
 130                     Messages.UNABLE_TO_MARSHAL_NON_ELEMENT.format(bean.getClass().getName()),
 131                     null,
 132                     null));
 133         }
 134         else {
 135             target.startElement(tagName,bean);
 136             target.childAsSoleContent(bean,null);
 137             target.endElement();
 138         }
 139     }
 140 
 141     public final void serializeURIs(BeanT bean, XMLSerializer target) throws SAXException {
 142         // TODO: maybe we should create another LeafBeanInfoImpl class for
 143         // context-dependent xducers?
 144         if(xducer.useNamespace()) {
 145             try {
 146                 xducer.declareNamespace(bean,target);
 147             } catch (AccessorException e) {
 148                 target.reportError(null,e);
 149             }
 150         }
 151     }
 152 
 153     public final Loader getLoader(JAXBContextImpl context, boolean typeSubstitutionCapable) {
 154         if(typeSubstitutionCapable)
 155             return loaderWithSubst;
 156         else
 157             return loader;
 158     }
 159 
 160     public Transducer<BeanT> getTransducer() {
 161         return xducer;
 162     }
 163 }