diff -r 000000000000 -r 373ffda63c9a src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/ClassBeanInfoImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/ClassBeanInfoImpl.java Wed Apr 27 01:27:09 2016 +0800 @@ -0,0 +1,439 @@ +/* + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.bind.v2.runtime; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.bind.ValidationEvent; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.helpers.ValidationEventImpl; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +import com.sun.istack.internal.FinalArrayList; +import com.sun.xml.internal.bind.Util; +import com.sun.xml.internal.bind.api.AccessorException; +import com.sun.xml.internal.bind.v2.ClassFactory; +import com.sun.xml.internal.bind.v2.WellKnownNamespace; +import com.sun.xml.internal.bind.v2.model.core.ID; +import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo; +import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo; +import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty; +import com.sun.xml.internal.bind.v2.runtime.property.Property; +import com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory; +import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; +import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader; +import com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader; +import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext; +import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader; + +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.LocatorImpl; + +/** + * {@link JaxBeanInfo} implementation for j2s bean. + * + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + */ +public final class ClassBeanInfoImpl extends JaxBeanInfo implements AttributeAccessor { + + /** + * Properties of this bean class but not its ancestor classes. + */ + public final Property[] properties; + + /** + * Non-null if this bean has an ID property. + */ + private Property idProperty; + + /** + * Immutable configured loader for this class. + * + *

+ * Set from the link method, but considered final. + */ + private Loader loader; + private Loader loaderWithTypeSubst; + + /** + * Set only until the link phase to avoid leaking memory. + */ + private RuntimeClassInfo ci; + + private final Accessor> inheritedAttWildcard; + private final Transducer xducer; + + /** + * {@link ClassBeanInfoImpl} that represents the super class of {@link #jaxbType}. + */ + public final ClassBeanInfoImpl superClazz; + + private final Accessor xmlLocatorField; + + private final Name tagName; + + private boolean retainPropertyInfo = false; + + /** + * The {@link AttributeProperty}s for this type and all its ancestors. + * If {@link JAXBContextImpl#c14nSupport} is true, this is sorted alphabetically. + */ + private /*final*/ AttributeProperty[] attributeProperties; + + /** + * {@link Property}s that need to receive {@link Property#serializeURIs(Object, XMLSerializer)} callback. + */ + private /*final*/ Property[] uriProperties; + + private final Method factoryMethod; + + /*package*/ ClassBeanInfoImpl(JAXBContextImpl owner, RuntimeClassInfo ci) { + super(owner,ci,ci.getClazz(),ci.getTypeName(),ci.isElement(),false,true); + + this.ci = ci; + this.inheritedAttWildcard = ci.getAttributeWildcard(); + this.xducer = ci.getTransducer(); + this.factoryMethod = ci.getFactoryMethod(); + this.retainPropertyInfo = owner.retainPropertyInfo; + + // make the factory accessible + if(factoryMethod!=null) { + int classMod = factoryMethod.getDeclaringClass().getModifiers(); + + if(!Modifier.isPublic(classMod) || !Modifier.isPublic(factoryMethod.getModifiers())) { + // attempt to make it work even if the constructor is not accessible + try { + factoryMethod.setAccessible(true); + } catch(SecurityException e) { + // but if we don't have a permission to do so, work gracefully. + logger.log(Level.FINE,"Unable to make the method of "+factoryMethod+" accessible",e); + throw e; + } + } + } + + + if(ci.getBaseClass()==null) + this.superClazz = null; + else + this.superClazz = owner.getOrCreate(ci.getBaseClass()); + + if(superClazz!=null && superClazz.xmlLocatorField!=null) + xmlLocatorField = superClazz.xmlLocatorField; + else + xmlLocatorField = ci.getLocatorField(); + + // create property objects + Collection ps = ci.getProperties(); + this.properties = new Property[ps.size()]; + int idx=0; + boolean elementOnly = true; + for( RuntimePropertyInfo info : ps ) { + Property p = PropertyFactory.create(owner,info); + if(info.id()==ID.ID) + idProperty = p; + properties[idx++] = p; + elementOnly &= info.elementOnlyContent(); + checkOverrideProperties(p); + } + // super class' idProperty might not be computed at this point, + // so check that later + + hasElementOnlyContentModel( elementOnly ); + // again update this value later when we know that of the super class + + if(ci.isElement()) + tagName = owner.nameBuilder.createElementName(ci.getElementName()); + else + tagName = null; + + setLifecycleFlags(); + } + + private void checkOverrideProperties(Property p) { + ClassBeanInfoImpl bi = this; + while ((bi = bi.superClazz) != null) { + Property[] props = bi.properties; + if (props == null) break; + for (Property superProperty : props) { + if (superProperty != null) { + String spName = superProperty.getFieldName(); + if ((spName != null) && (spName.equals(p.getFieldName()))) { + superProperty.setHiddenByOverride(true); + } + } + } + } + } + + @Override + protected void link(JAXBContextImpl grammar) { + if(uriProperties!=null) + return; // avoid linking twice + + super.link(grammar); + + if(superClazz!=null) + superClazz.link(grammar); + + getLoader(grammar,true); // make sure to build the loader if we haven't done so. + + // propagate values from super class + if(superClazz!=null) { + if(idProperty==null) + idProperty = superClazz.idProperty; + + if(!superClazz.hasElementOnlyContentModel()) + hasElementOnlyContentModel(false); + } + + // create a list of attribute/URI handlers + List attProps = new FinalArrayList(); + List uriProps = new FinalArrayList(); + for (ClassBeanInfoImpl bi = this; bi != null; bi = bi.superClazz) { + for (int i = 0; i < bi.properties.length; i++) { + Property p = bi.properties[i]; + if(p instanceof AttributeProperty) + attProps.add((AttributeProperty) p); + if(p.hasSerializeURIAction()) + uriProps.add(p); + } + } + if(grammar.c14nSupport) + Collections.sort(attProps); + + if(attProps.isEmpty()) + attributeProperties = EMPTY_PROPERTIES; + else + attributeProperties = attProps.toArray(new AttributeProperty[attProps.size()]); + + if(uriProps.isEmpty()) + uriProperties = EMPTY_PROPERTIES; + else + uriProperties = uriProps.toArray(new Property[uriProps.size()]); + } + + @Override + public void wrapUp() { + for (Property p : properties) + p.wrapUp(); + ci = null; + super.wrapUp(); + } + + public String getElementNamespaceURI(BeanT bean) { + return tagName.nsUri; + } + + public String getElementLocalName(BeanT bean) { + return tagName.localName; + } + + public BeanT createInstance(UnmarshallingContext context) throws IllegalAccessException, InvocationTargetException, InstantiationException, SAXException { + + BeanT bean = null; + if (factoryMethod == null){ + bean = ClassFactory.create0(jaxbType); + }else { + Object o = ClassFactory.create(factoryMethod); + if( jaxbType.isInstance(o) ){ + bean = (BeanT)o; + } else { + throw new InstantiationException("The factory method didn't return a correct object"); + } + } + + if(xmlLocatorField!=null) + // need to copy because Locator is mutable + try { + xmlLocatorField.set(bean,new LocatorImpl(context.getLocator())); + } catch (AccessorException e) { + context.handleError(e); + } + return bean; + } + + public boolean reset(BeanT bean, UnmarshallingContext context) throws SAXException { + try { + if(superClazz!=null) + superClazz.reset(bean,context); + for( Property p : properties ) + p.reset(bean); + return true; + } catch (AccessorException e) { + context.handleError(e); + return false; + } + } + + public String getId(BeanT bean, XMLSerializer target) throws SAXException { + if(idProperty!=null) { + try { + return idProperty.getIdValue(bean); + } catch (AccessorException e) { + target.reportError(null,e); + } + } + return null; + } + + public void serializeRoot(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException { + if(tagName==null) { + Class beanClass = bean.getClass(); + String message; + if (beanClass.isAnnotationPresent(XmlRootElement.class)) { + message = Messages.UNABLE_TO_MARSHAL_UNBOUND_CLASS.format(beanClass.getName()); + } else { + message = Messages.UNABLE_TO_MARSHAL_NON_ELEMENT.format(beanClass.getName()); + } + target.reportError(new ValidationEventImpl(ValidationEvent.ERROR,message,null, null)); + } else { + target.startElement(tagName,bean); + target.childAsSoleContent(bean,null); + target.endElement(); + if (retainPropertyInfo) { + target.currentProperty.remove(); + } + } + } + + public void serializeBody(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException { + if (superClazz != null) { + superClazz.serializeBody(bean, target); + } + try { + for (Property p : properties) { + if (retainPropertyInfo) { + target.currentProperty.set(p); + } + boolean isThereAnOverridingProperty = p.isHiddenByOverride(); + if (!isThereAnOverridingProperty || bean.getClass().equals(jaxbType)) { + p.serializeBody(bean, target, null); + } else if (isThereAnOverridingProperty) { + // 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 + Class beanClass = bean.getClass(); + if (Utils.REFLECTION_NAVIGATOR.getDeclaredField(beanClass, p.getFieldName()) == null) { + p.serializeBody(bean, target, null); + } + } + } + } catch (AccessorException e) { + target.reportError(null, e); + } + } + + public void serializeAttributes(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException { + for( AttributeProperty p : attributeProperties ) + try { + if (retainPropertyInfo) { + final Property parentProperty = target.getCurrentProperty(); + target.currentProperty.set(p); + p.serializeAttributes(bean,target); + target.currentProperty.set(parentProperty); + } else { + p.serializeAttributes(bean,target); + } + if (p.attName.equals(WellKnownNamespace.XML_SCHEMA_INSTANCE, "nil")) { + isNilIncluded = true; + } + } catch (AccessorException e) { + target.reportError(null,e); + } + + try { + if(inheritedAttWildcard!=null) { + Map map = inheritedAttWildcard.get(bean); + target.attWildcardAsAttributes(map,null); + } + } catch (AccessorException e) { + target.reportError(null,e); + } + } + + public void serializeURIs(BeanT bean, XMLSerializer target) throws SAXException { + try { + if (retainPropertyInfo) { + final Property parentProperty = target.getCurrentProperty(); + for( Property p : uriProperties ) { + target.currentProperty.set(p); + p.serializeURIs(bean,target); + } + target.currentProperty.set(parentProperty); + } else { + for( Property p : uriProperties ) { + p.serializeURIs(bean,target); + } + } + if(inheritedAttWildcard!=null) { + Map map = inheritedAttWildcard.get(bean); + target.attWildcardAsURIs(map,null); + } + } catch (AccessorException e) { + target.reportError(null,e); + } + } + + public Loader getLoader(JAXBContextImpl context, boolean typeSubstitutionCapable) { + if(loader==null) { + // these variables have to be set before they are initialized, + // because the initialization may build other loaders and they may refer to this. + StructureLoader sl = new StructureLoader(this); + loader = sl; + if(ci.hasSubClasses()) + loaderWithTypeSubst = new XsiTypeLoader(this); + else + // optimization. we know there can be no @xsi:type + loaderWithTypeSubst = loader; + + + sl.init(context,this,ci.getAttributeWildcard()); + } + if(typeSubstitutionCapable) + return loaderWithTypeSubst; + else + return loader; + } + + public Transducer getTransducer() { + return xducer; + } + + private static final AttributeProperty[] EMPTY_PROPERTIES = new AttributeProperty[0]; + + private static final Logger logger = Util.getClassLogger(); + +}