001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.bind.v2.runtime.property;
027:
028: import java.io.IOException;
029:
030: import javax.xml.bind.JAXBElement;
031: import javax.xml.bind.JAXBException;
032: import javax.xml.bind.annotation.DomHandler;
033: import javax.xml.stream.XMLStreamException;
034:
035: import com.sun.xml.internal.bind.api.AccessorException;
036: import com.sun.xml.internal.bind.v2.ClassFactory;
037: import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
038: import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
039: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElement;
040: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeReferencePropertyInfo;
041: import com.sun.xml.internal.bind.v2.runtime.ElementBeanInfoImpl;
042: import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
043: import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
044: import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
045: import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
046: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.ChildLoader;
047: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.WildcardLoader;
048: import com.sun.xml.internal.bind.v2.util.QNameMap;
049:
050: import org.xml.sax.SAXException;
051:
052: /**
053: * @author Kohsuke Kawaguchi
054: */
055: final class SingleReferenceNodeProperty<BeanT, ValueT> extends
056: PropertyImpl<BeanT> {
057:
058: private final Accessor<BeanT, ValueT> acc;
059:
060: private final QNameMap<JaxBeanInfo> expectedElements = new QNameMap<JaxBeanInfo>();
061:
062: private final DomHandler domHandler;
063: private final WildcardMode wcMode;
064:
065: public SingleReferenceNodeProperty(JAXBContextImpl p,
066: RuntimeReferencePropertyInfo prop) {
067: super (p, prop);
068: acc = prop.getAccessor().optimize();
069:
070: for (RuntimeElement e : prop.getElements()) {
071: expectedElements.put(e.getElementName(), p.getOrCreate(e));
072: }
073:
074: if (prop.getWildcard() != null) {
075: domHandler = (DomHandler) ClassFactory.create(prop
076: .getDOMHandler());
077: wcMode = prop.getWildcard();
078: } else {
079: domHandler = null;
080: wcMode = null;
081: }
082: }
083:
084: public void reset(BeanT bean) throws AccessorException {
085: acc.set(bean, null);
086: }
087:
088: public String getIdValue(BeanT beanT) {
089: return null;
090: }
091:
092: public void serializeBody(BeanT o, XMLSerializer w, Object outerPeer)
093: throws SAXException, AccessorException, IOException,
094: XMLStreamException {
095: ValueT v = acc.get(o);
096: if (v != null) {
097: try {
098: JaxBeanInfo bi = w.grammar.getBeanInfo(v, true);
099: if (bi.jaxbType == Object.class && domHandler != null)
100: // even if 'v' is a DOM node, it always derive from Object,
101: // so the getBeanInfo returns BeanInfo for Object
102: w.writeDom(v, domHandler, o, fieldName);
103: else
104: bi.serializeRoot(v, w);
105: } catch (JAXBException e) {
106: w.reportError(fieldName, e);
107: // recover by ignoring this property
108: }
109: }
110: }
111:
112: public void buildChildElementUnmarshallers(UnmarshallerChain chain,
113: QNameMap<ChildLoader> handlers) {
114: for (QNameMap.Entry<JaxBeanInfo> n : expectedElements
115: .entrySet())
116: handlers.put(n.nsUri, n.localName, new ChildLoader(n
117: .getValue().getLoader(chain.context, true), acc));
118:
119: if (domHandler != null)
120: handlers.put(CATCH_ALL, new ChildLoader(new WildcardLoader(
121: domHandler, wcMode), acc));
122:
123: }
124:
125: public PropertyKind getKind() {
126: return PropertyKind.REFERENCE;
127: }
128:
129: @Override
130: public Accessor getElementPropertyAccessor(String nsUri,
131: String localName) {
132: JaxBeanInfo bi = expectedElements.get(nsUri, localName);
133: if (bi != null) {
134: if (bi instanceof ElementBeanInfoImpl) {
135: final ElementBeanInfoImpl ebi = (ElementBeanInfoImpl) bi;
136: // a JAXBElement. We need to handle JAXBElement for JAX-WS
137: return new Accessor<BeanT, Object>(ebi.expectedType) {
138: public Object get(BeanT bean)
139: throws AccessorException {
140: ValueT r = acc.get(bean);
141: if (r instanceof JAXBElement) {
142: return ((JAXBElement) r).getValue();
143: } else
144: // this is sloppy programming, but hey...
145: return r;
146: }
147:
148: public void set(BeanT bean, Object value)
149: throws AccessorException {
150: if (value != null) {
151: value = ebi.createInstanceFromValue(value);
152: }
153: acc.set(bean, (ValueT) value);
154: }
155: };
156: } else {
157: // a custom element type, like @XmlRootElement class Foo { ... }
158: return acc;
159: }
160: } else
161: return null;
162: }
163: }
|