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