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

changeset 286
f50545b5e2f1
child 368
0989ad8c0860
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;
27
28 import java.io.IOException;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.logging.Level;
37 import java.util.logging.Logger;
38
39 import javax.xml.bind.ValidationEvent;
40 import javax.xml.bind.annotation.XmlRootElement;
41 import javax.xml.bind.helpers.ValidationEventImpl;
42 import javax.xml.namespace.QName;
43 import javax.xml.stream.XMLStreamException;
44
45 import com.sun.istack.internal.FinalArrayList;
46 import com.sun.xml.internal.bind.Util;
47 import com.sun.xml.internal.bind.api.AccessorException;
48 import com.sun.xml.internal.bind.v2.ClassFactory;
49 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
50 import com.sun.xml.internal.bind.v2.model.core.ID;
51 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo;
52 import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
53 import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty;
54 import com.sun.xml.internal.bind.v2.runtime.property.Property;
55 import com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory;
56 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
57 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
58 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader;
59 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
60 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader;
61
62 import org.xml.sax.Locator;
63 import org.xml.sax.SAXException;
64 import org.xml.sax.helpers.LocatorImpl;
65
66 /**
67 * {@link JaxBeanInfo} implementation for j2s bean.
68 *
69 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
70 */
71 public final class ClassBeanInfoImpl<BeanT> extends JaxBeanInfo<BeanT> implements AttributeAccessor<BeanT> {
72
73 /**
74 * Properties of this bean class but not its ancestor classes.
75 */
76 public final Property<BeanT>[] properties;
77
78 /**
79 * Non-null if this bean has an ID property.
80 */
81 private Property<? super BeanT> idProperty;
82
83 /**
84 * Immutable configured loader for this class.
85 *
86 * <p>
87 * Set from the link method, but considered final.
88 */
89 private Loader loader;
90 private Loader loaderWithTypeSubst;
91
92 /**
93 * Set only until the link phase to avoid leaking memory.
94 */
95 private RuntimeClassInfo ci;
96
97 private final Accessor<? super BeanT,Map<QName,String>> inheritedAttWildcard;
98 private final Transducer<BeanT> xducer;
99
100 /**
101 * {@link ClassBeanInfoImpl} that represents the super class of {@link #jaxbType}.
102 */
103 public final ClassBeanInfoImpl<? super BeanT> superClazz;
104
105 private final Accessor<? super BeanT,Locator> xmlLocatorField;
106
107 private final Name tagName;
108
109 private boolean retainPropertyInfo = false;
110
111 /**
112 * The {@link AttributeProperty}s for this type and all its ancestors.
113 * If {@link JAXBContextImpl#c14nSupport} is true, this is sorted alphabetically.
114 */
115 private /*final*/ AttributeProperty<BeanT>[] attributeProperties;
116
117 /**
118 * {@link Property}s that need to receive {@link Property#serializeURIs(Object, XMLSerializer)} callback.
119 */
120 private /*final*/ Property<BeanT>[] uriProperties;
121
122 private final Method factoryMethod;
123
124 /*package*/ ClassBeanInfoImpl(JAXBContextImpl owner, RuntimeClassInfo ci) {
125 super(owner,ci,ci.getClazz(),ci.getTypeName(),ci.isElement(),false,true);
126
127 this.ci = ci;
128 this.inheritedAttWildcard = ci.getAttributeWildcard();
129 this.xducer = ci.getTransducer();
130 this.factoryMethod = ci.getFactoryMethod();
131 this.retainPropertyInfo = owner.retainPropertyInfo;
132
133 // make the factory accessible
134 if(factoryMethod!=null) {
135 int classMod = factoryMethod.getDeclaringClass().getModifiers();
136
137 if(!Modifier.isPublic(classMod) || !Modifier.isPublic(factoryMethod.getModifiers())) {
138 // attempt to make it work even if the constructor is not accessible
139 try {
140 factoryMethod.setAccessible(true);
141 } catch(SecurityException e) {
142 // but if we don't have a permission to do so, work gracefully.
143 logger.log(Level.FINE,"Unable to make the method of "+factoryMethod+" accessible",e);
144 throw e;
145 }
146 }
147 }
148
149
150 if(ci.getBaseClass()==null)
151 this.superClazz = null;
152 else
153 this.superClazz = owner.getOrCreate(ci.getBaseClass());
154
155 if(superClazz!=null && superClazz.xmlLocatorField!=null)
156 xmlLocatorField = superClazz.xmlLocatorField;
157 else
158 xmlLocatorField = ci.getLocatorField();
159
160 // create property objects
161 Collection<? extends RuntimePropertyInfo> ps = ci.getProperties();
162 this.properties = new Property[ps.size()];
163 int idx=0;
164 boolean elementOnly = true;
165 for( RuntimePropertyInfo info : ps ) {
166 Property p = PropertyFactory.create(owner,info);
167 if(info.id()==ID.ID)
168 idProperty = p;
169 properties[idx++] = p;
170 elementOnly &= info.elementOnlyContent();
171 checkOverrideProperties(p);
172 }
173 // super class' idProperty might not be computed at this point,
174 // so check that later
175
176 hasElementOnlyContentModel( elementOnly );
177 // again update this value later when we know that of the super class
178
179 if(ci.isElement())
180 tagName = owner.nameBuilder.createElementName(ci.getElementName());
181 else
182 tagName = null;
183
184 setLifecycleFlags();
185 }
186
187 private void checkOverrideProperties(Property p) {
188 ClassBeanInfoImpl bi = this;
189 while ((bi = bi.superClazz) != null) {
190 Property[] props = bi.properties;
191 if (props == null) break;
192 for (Property superProperty : props) {
193 if (superProperty == null) break;
194 String spName = superProperty.getFieldName();
195 if ((spName != null) && (spName.equals(p.getFieldName()))) {
196 superProperty.setHiddenByOverride(true);
197 }
198 }
199 }
200 }
201
202 @Override
203 protected void link(JAXBContextImpl grammar) {
204 if(uriProperties!=null)
205 return; // avoid linking twice
206
207 super.link(grammar);
208
209 if(superClazz!=null)
210 superClazz.link(grammar);
211
212 getLoader(grammar,true); // make sure to build the loader if we haven't done so.
213
214 // propagate values from super class
215 if(superClazz!=null) {
216 if(idProperty==null)
217 idProperty = superClazz.idProperty;
218
219 if(!superClazz.hasElementOnlyContentModel())
220 hasElementOnlyContentModel(false);
221 }
222
223 // create a list of attribute/URI handlers
224 List<AttributeProperty> attProps = new FinalArrayList<AttributeProperty>();
225 List<Property> uriProps = new FinalArrayList<Property>();
226 for (ClassBeanInfoImpl bi = this; bi != null; bi = bi.superClazz) {
227 for (int i = 0; i < bi.properties.length; i++) {
228 Property p = bi.properties[i];
229 if(p instanceof AttributeProperty)
230 attProps.add((AttributeProperty) p);
231 if(p.hasSerializeURIAction())
232 uriProps.add(p);
233 }
234 }
235 if(grammar.c14nSupport)
236 Collections.sort(attProps);
237
238 if(attProps.isEmpty())
239 attributeProperties = EMPTY_PROPERTIES;
240 else
241 attributeProperties = attProps.toArray(new AttributeProperty[attProps.size()]);
242
243 if(uriProps.isEmpty())
244 uriProperties = EMPTY_PROPERTIES;
245 else
246 uriProperties = uriProps.toArray(new Property[uriProps.size()]);
247 }
248
249 @Override
250 public void wrapUp() {
251 for (Property p : properties)
252 p.wrapUp();
253 ci = null;
254 super.wrapUp();
255 }
256
257 public String getElementNamespaceURI(BeanT bean) {
258 return tagName.nsUri;
259 }
260
261 public String getElementLocalName(BeanT bean) {
262 return tagName.localName;
263 }
264
265 public BeanT createInstance(UnmarshallingContext context) throws IllegalAccessException, InvocationTargetException, InstantiationException, SAXException {
266
267 BeanT bean = null;
268 if (factoryMethod == null){
269 bean = ClassFactory.create0(jaxbType);
270 }else {
271 Object o = ClassFactory.create(factoryMethod);
272 if( jaxbType.isInstance(o) ){
273 bean = (BeanT)o;
274 } else {
275 throw new InstantiationException("The factory method didn't return a correct object");
276 }
277 }
278
279 if(xmlLocatorField!=null)
280 // need to copy because Locator is mutable
281 try {
282 xmlLocatorField.set(bean,new LocatorImpl(context.getLocator()));
283 } catch (AccessorException e) {
284 context.handleError(e);
285 }
286 return bean;
287 }
288
289 public boolean reset(BeanT bean, UnmarshallingContext context) throws SAXException {
290 try {
291 if(superClazz!=null)
292 superClazz.reset(bean,context);
293 for( Property<BeanT> p : properties )
294 p.reset(bean);
295 return true;
296 } catch (AccessorException e) {
297 context.handleError(e);
298 return false;
299 }
300 }
301
302 public String getId(BeanT bean, XMLSerializer target) throws SAXException {
303 if(idProperty!=null) {
304 try {
305 return idProperty.getIdValue(bean);
306 } catch (AccessorException e) {
307 target.reportError(null,e);
308 }
309 }
310 return null;
311 }
312
313 public void serializeRoot(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
314 if(tagName==null) {
315 Class beanClass = bean.getClass();
316 String message;
317 if (beanClass.isAnnotationPresent(XmlRootElement.class)) {
318 message = Messages.UNABLE_TO_MARSHAL_UNBOUND_CLASS.format(beanClass.getName());
319 } else {
320 message = Messages.UNABLE_TO_MARSHAL_NON_ELEMENT.format(beanClass.getName());
321 }
322 target.reportError(new ValidationEventImpl(ValidationEvent.ERROR,message,null, null));
323 } else {
324 target.startElement(tagName,bean);
325 target.childAsSoleContent(bean,null);
326 target.endElement();
327 if (retainPropertyInfo) {
328 target.currentProperty.remove();
329 }
330 }
331 }
332
333 public void serializeBody(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
334 if (superClazz != null) {
335 superClazz.serializeBody(bean, target);
336 }
337 try {
338 for (Property<BeanT> p : properties) {
339 if (retainPropertyInfo) {
340 target.currentProperty.set(p);
341 }
342 if (!(p.isHiddenByOverride() && !bean.getClass().equals(jaxbType))) {
343 p.serializeBody(bean, target, null);
344 }
345 }
346 } catch (AccessorException e) {
347 target.reportError(null, e);
348 }
349 }
350
351 public void serializeAttributes(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
352 for( AttributeProperty<BeanT> p : attributeProperties )
353 try {
354 if (retainPropertyInfo) {
355 final Property parentProperty = target.getCurrentProperty();
356 target.currentProperty.set(p);
357 p.serializeAttributes(bean,target);
358 target.currentProperty.set(parentProperty);
359 } else {
360 p.serializeAttributes(bean,target);
361 }
362 if (p.attName.equals(WellKnownNamespace.XML_SCHEMA_INSTANCE, "nil")) {
363 isNilIncluded = true;
364 }
365 } catch (AccessorException e) {
366 target.reportError(null,e);
367 }
368
369 try {
370 if(inheritedAttWildcard!=null) {
371 Map<QName,String> map = inheritedAttWildcard.get(bean);
372 target.attWildcardAsAttributes(map,null);
373 }
374 } catch (AccessorException e) {
375 target.reportError(null,e);
376 }
377 }
378
379 public void serializeURIs(BeanT bean, XMLSerializer target) throws SAXException {
380 try {
381 if (retainPropertyInfo) {
382 final Property parentProperty = target.getCurrentProperty();
383 for( Property<BeanT> p : uriProperties ) {
384 target.currentProperty.set(p);
385 p.serializeURIs(bean,target);
386 }
387 target.currentProperty.set(parentProperty);
388 } else {
389 for( Property<BeanT> p : uriProperties ) {
390 p.serializeURIs(bean,target);
391 }
392 }
393 if(inheritedAttWildcard!=null) {
394 Map<QName,String> map = inheritedAttWildcard.get(bean);
395 target.attWildcardAsURIs(map,null);
396 }
397 } catch (AccessorException e) {
398 target.reportError(null,e);
399 }
400 }
401
402 public Loader getLoader(JAXBContextImpl context, boolean typeSubstitutionCapable) {
403 if(loader==null) {
404 // these variables have to be set before they are initialized,
405 // because the initialization may build other loaders and they may refer to this.
406 StructureLoader sl = new StructureLoader(this);
407 loader = sl;
408 if(ci.hasSubClasses())
409 loaderWithTypeSubst = new XsiTypeLoader(this);
410 else
411 // optimization. we know there can be no @xsi:type
412 loaderWithTypeSubst = loader;
413
414
415 sl.init(context,this,ci.getAttributeWildcard());
416 }
417 if(typeSubstitutionCapable)
418 return loaderWithTypeSubst;
419 else
420 return loader;
421 }
422
423 public Transducer<BeanT> getTransducer() {
424 return xducer;
425 }
426
427 private static final AttributeProperty[] EMPTY_PROPERTIES = new AttributeProperty[0];
428
429 private static final Logger logger = Util.getClassLogger();
430
431 }

mercurial