001: /*
002: * Copyright (c) 1998-2007 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong
028: */
029:
030: package com.caucho.jaxb.mapping;
031:
032: import com.caucho.jaxb.BinderImpl;
033: import com.caucho.jaxb.JAXBContextImpl;
034: import com.caucho.jaxb.JAXBUtil;
035: import com.caucho.util.L10N;
036: import com.caucho.xml.stream.StaxUtil;
037:
038: import org.w3c.dom.Node;
039:
040: import static javax.xml.XMLConstants.*;
041:
042: import javax.xml.bind.JAXBElement;
043: import javax.xml.bind.JAXBException;
044: import javax.xml.bind.Marshaller;
045: import javax.xml.bind.Unmarshaller;
046: import javax.xml.bind.UnmarshalException;
047:
048: import javax.xml.bind.annotation.XmlElement;
049: import javax.xml.bind.annotation.XmlElements;
050: import javax.xml.bind.annotation.XmlList;
051:
052: import javax.xml.namespace.QName;
053:
054: import javax.xml.stream.XMLStreamException;
055: import javax.xml.stream.XMLStreamReader;
056: import javax.xml.stream.XMLStreamWriter;
057:
058: import java.lang.annotation.Annotation;
059:
060: import java.io.IOException;
061:
062: import java.util.Collection;
063: import java.util.LinkedHashMap;
064: import java.util.List;
065: import java.util.Map;
066:
067: import com.caucho.jaxb.accessor.Accessor;
068:
069: import com.caucho.jaxb.property.ArrayProperty;
070: import com.caucho.jaxb.property.ListProperty;
071: import com.caucho.jaxb.property.MultiProperty;
072: import com.caucho.jaxb.property.Property;
073:
074: import com.caucho.jaxb.skeleton.ClassSkeleton;
075:
076: public class ElementsMapping extends XmlMapping {
077: private static final L10N L = new L10N(ElementsMapping.class);
078:
079: private Map<Class, QName> _qnameMap;
080:
081: public ElementsMapping(JAXBContextImpl context, Accessor accessor)
082: throws JAXBException {
083: super (context, accessor);
084:
085: if (accessor.getAnnotation(XmlList.class) != null)
086: throw new JAXBException(L
087: .l("@XmlList cannot be used with @XmlElements"));
088:
089: XmlElements elements = accessor
090: .getAnnotation(XmlElements.class);
091:
092: if (elements.value().length == 0) {
093: // XXX special case : equivalent to unannotated
094: }
095:
096: if (elements.value().length == 1) {
097: // XXX special case : equivalent to @XmlElement
098: }
099:
100: _qnameMap = new LinkedHashMap<Class, QName>();
101: Map<QName, Property> qnameToPropertyMap = new LinkedHashMap<QName, Property>();
102: Map<Class, Property> classToPropertyMap = new LinkedHashMap<Class, Property>();
103:
104: for (XmlElement element : elements.value()) {
105: if (XmlElement.DEFAULT.class.equals(element.type()))
106: throw new JAXBException(
107: L
108: .l("@XmlElement annotations in @XmlElements must specify a type"));
109:
110: QName qname = qnameFromXmlElement(element);
111: Property property = _context.createProperty(element.type());
112:
113: qnameToPropertyMap.put(qname, property);
114: classToPropertyMap.put(element.type(), property);
115: _qnameMap.put(element.type(), qname);
116:
117: if (!property.isXmlPrimitiveType())
118: _context.createSkeleton(element.type());
119: }
120:
121: _property = new MultiProperty(qnameToPropertyMap,
122: classToPropertyMap);
123:
124: if (List.class.isAssignableFrom(accessor.getType()))
125: _property = new ListProperty(_property);
126:
127: else if (accessor.getType().isArray()) {
128: Class cType = accessor.getType().getComponentType();
129: _property = ArrayProperty.createArrayProperty(_property,
130: cType);
131: }
132:
133: // XXX Wrapper
134: }
135:
136: public void putQNames(Map<QName, XmlMapping> map)
137: throws JAXBException {
138: for (QName qname : _qnameMap.values()) {
139: if (map.containsKey(qname))
140: throw new JAXBException(
141: L
142: .l(
143: "Class contains two elements with the same QName {0}",
144: qname));
145:
146: map.put(qname, this );
147: }
148: }
149:
150: public void generateSchema(XMLStreamWriter out)
151: throws JAXBException, XMLStreamException {
152: out.writeStartElement(XML_SCHEMA_PREFIX, "choice",
153: W3C_XML_SCHEMA_NS_URI);
154: out.writeAttribute("minOccurs", "0");
155:
156: if (_property.getMaxOccurs() != null)
157: out.writeAttribute("maxOccurs", _property.getMaxOccurs());
158:
159: MultiProperty multiProperty = null;
160:
161: if (_property instanceof ListProperty) {
162: ListProperty listProperty = (ListProperty) _property;
163: multiProperty = (MultiProperty) listProperty
164: .getComponentProperty();
165: } else
166: multiProperty = (MultiProperty) _property;
167:
168: Collection<Property> properties = multiProperty.getProperties();
169:
170: XmlElements xmlElements = _accessor
171: .getAnnotation(XmlElements.class);
172: XmlElement[] elements = xmlElements.value();
173:
174: int i = 0;
175:
176: for (Property property : properties) {
177: out.writeEmptyElement(XML_SCHEMA_PREFIX, "element",
178: W3C_XML_SCHEMA_NS_URI);
179:
180: String type = StaxUtil.qnameToString(out, property
181: .getSchemaType());
182:
183: out.writeAttribute("type", type);
184:
185: if ("##default".equals(elements[i].name()))
186: out.writeAttribute("name", _accessor.getName());
187: else
188: // XXX namespace
189: out.writeAttribute("name", elements[i].name());
190:
191: i++;
192: }
193:
194: out.writeEndElement(); // choice
195: }
196:
197: public QName getQName(Object obj) throws JAXBException {
198: return _qnameMap.get(obj.getClass());
199: }
200: }
|