src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/ArrayElementProperty.java

changeset 286
f50545b5e2f1
parent 0
373ffda63c9a
equal deleted inserted replaced
284:88b85470e72c 286:f50545b5e2f1
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 */
25
26 package com.sun.xml.internal.bind.v2.runtime.property;
27
28 import java.io.IOException;
29 import java.lang.reflect.Type;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33
34 import javax.xml.bind.JAXBException;
35 import javax.xml.stream.XMLStreamException;
36
37 import com.sun.xml.internal.bind.api.AccessorException;
38 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
39 import com.sun.xml.internal.bind.v2.model.core.TypeRef;
40 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementPropertyInfo;
41 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeRef;
42 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
43 import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
44 import com.sun.xml.internal.bind.v2.runtime.Name;
45 import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil;
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.reflect.Accessor;
49 import com.sun.xml.internal.bind.v2.runtime.reflect.ListIterator;
50 import com.sun.xml.internal.bind.v2.runtime.reflect.Lister;
51 import com.sun.xml.internal.bind.v2.runtime.reflect.NullSafeAccessor;
52 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.ChildLoader;
53 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.DefaultValueLoaderDecorator;
54 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
55 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Receiver;
56 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.TextLoader;
57 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader;
58 import com.sun.xml.internal.bind.v2.util.QNameMap;
59
60 import org.xml.sax.SAXException;
61
62 /**
63 * {@link Property} implementation for multi-value property that maps to an element.
64 *
65 * @author Kohsuke Kawaguchi
66 */
67 abstract class ArrayElementProperty<BeanT,ListT,ItemT> extends ArrayERProperty<BeanT,ListT,ItemT> {
68
69 private final Map<Class,TagAndType> typeMap = new HashMap<Class,TagAndType>();
70 /**
71 * Set by the constructor and reset in the {@link #wrapUp()} method.
72 */
73 private Map<TypeRef<Type,Class>,JaxBeanInfo> refs = new HashMap<TypeRef<Type, Class>, JaxBeanInfo>();
74 /**
75 * Set by the constructor and reset in the {@link #wrapUp()} method.
76 */
77 protected RuntimeElementPropertyInfo prop;
78
79 /**
80 * Tag name used when we see null in the collection. Can be null.
81 */
82 private final Name nillableTagName;
83
84 protected ArrayElementProperty(JAXBContextImpl grammar, RuntimeElementPropertyInfo prop) {
85 super(grammar, prop, prop.getXmlName(), prop.isCollectionNillable());
86 this.prop = prop;
87
88 List<? extends RuntimeTypeRef> types = prop.getTypes();
89
90 Name n = null;
91
92 for (RuntimeTypeRef typeRef : types) {
93 Class type = (Class)typeRef.getTarget().getType();
94 if(type.isPrimitive())
95 type = RuntimeUtil.primitiveToBox.get(type);
96
97 JaxBeanInfo beanInfo = grammar.getOrCreate(typeRef.getTarget());
98 TagAndType tt = new TagAndType(
99 grammar.nameBuilder.createElementName(typeRef.getTagName()),
100 beanInfo);
101 typeMap.put(type,tt);
102 refs.put(typeRef,beanInfo);
103 if(typeRef.isNillable() && n==null)
104 n = tt.tagName;
105 }
106
107 nillableTagName = n;
108 }
109
110 @Override
111 public void wrapUp() {
112 super.wrapUp();
113 refs = null;
114 prop = null; // avoid keeping model objects live
115 }
116
117 protected void serializeListBody(BeanT beanT, XMLSerializer w, ListT list) throws IOException, XMLStreamException, SAXException, AccessorException {
118 ListIterator<ItemT> itr = lister.iterator(list, w);
119
120 boolean isIdref = itr instanceof Lister.IDREFSIterator; // UGLY
121
122 while(itr.hasNext()) {
123 try {
124 ItemT item = itr.next();
125 if (item != null) {
126 Class itemType = item.getClass();
127 if(isIdref)
128 // This should be the only place where we need to be aware
129 // that the iterator is iterating IDREFS.
130 itemType = ((Lister.IDREFSIterator)itr).last().getClass();
131
132 // normally, this returns non-null
133 TagAndType tt = typeMap.get(itemType);
134 while(tt==null && itemType!=null) {
135 // otherwise we'll just have to try the slow way
136 itemType = itemType.getSuperclass();
137 tt = typeMap.get(itemType);
138 }
139
140 if(tt==null) {
141 // item is not of the expected type.
142 // w.reportError(new ValidationEventImpl(ValidationEvent.ERROR,
143 // Messages.UNEXPECTED_JAVA_TYPE.format(
144 // item.getClass().getName(),
145 // getExpectedClassNameList()
146 // ),
147 // w.getCurrentLocation(fieldName)));
148 // continue;
149
150 // see the similar code in SingleElementNodeProperty.
151 // for the purpose of simple type substitution, make it a non-error
152
153 w.startElement(typeMap.values().iterator().next().tagName,null);
154 w.childAsXsiType(item,fieldName,w.grammar.getBeanInfo(Object.class), false);
155 } else {
156 w.startElement(tt.tagName,null);
157 serializeItem(tt.beanInfo,item,w);
158 }
159
160 w.endElement();
161 } else {
162 if(nillableTagName!=null) {
163 w.startElement(nillableTagName,null);
164 w.writeXsiNilTrue();
165 w.endElement();
166 }
167 }
168 } catch (JAXBException e) {
169 w.reportError(fieldName,e);
170 // recover by ignoring this item
171 }
172 }
173 }
174
175 /**
176 * Serializes one item of the property.
177 */
178 protected abstract void serializeItem(JaxBeanInfo expected, ItemT item, XMLSerializer w) throws SAXException, AccessorException, IOException, XMLStreamException;
179
180
181 public void createBodyUnmarshaller(UnmarshallerChain chain, QNameMap<ChildLoader> loaders) {
182
183 // all items go to the same lister,
184 // so they should share the same offset.
185 int offset = chain.allocateOffset();
186 Receiver recv = new ReceiverImpl(offset);
187
188 for (RuntimeTypeRef typeRef : prop.getTypes()) {
189
190 Name tagName = chain.context.nameBuilder.createElementName(typeRef.getTagName());
191 Loader item = createItemUnmarshaller(chain,typeRef);
192
193 if(typeRef.isNillable() || chain.context.allNillable)
194 item = new XsiNilLoader.Array(item);
195 if(typeRef.getDefaultValue()!=null)
196 item = new DefaultValueLoaderDecorator(item,typeRef.getDefaultValue());
197
198 loaders.put(tagName,new ChildLoader(item,recv));
199 }
200 }
201
202 public final PropertyKind getKind() {
203 return PropertyKind.ELEMENT;
204 }
205
206 /**
207 * Creates a loader handler that unmarshals the body of the item.
208 *
209 * <p>
210 * This will be sandwiched into <item> ... </item>.
211 *
212 * <p>
213 * When unmarshalling the body of item, the Pack of {@link Lister} is available
214 * as the handler state.
215 *
216 * @param chain
217 * @param typeRef
218 */
219 private Loader createItemUnmarshaller(UnmarshallerChain chain, RuntimeTypeRef typeRef) {
220 if(PropertyFactory.isLeaf(typeRef.getSource())) {
221 final Transducer xducer = typeRef.getTransducer();
222 return new TextLoader(xducer);
223 } else {
224 return refs.get(typeRef).getLoader(chain.context,true);
225 }
226 }
227
228 public Accessor getElementPropertyAccessor(String nsUri, String localName) {
229 if(wrapperTagName!=null) {
230 if(wrapperTagName.equals(nsUri,localName))
231 return acc;
232 } else {
233 for (TagAndType tt : typeMap.values()) {
234 if(tt.tagName.equals(nsUri,localName))
235 // when we can't distinguish null and empty list, JAX-WS doesn't want to see
236 // null (just like any user apps), but since we are providing a raw accessor,
237 // which just grabs the value from the field, we wrap it so that it won't return
238 // null.
239 return new NullSafeAccessor<BeanT,ListT,Object>(acc,lister);
240 }
241 }
242 return null;
243 }
244 }

mercurial