All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.jaxb.runtime.v2.runtime.ClassBeanInfoImpl Maven / Gradle / Ivy

/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.jaxb.runtime.v2.runtime;

import com.sun.istack.FinalArrayList;
import org.glassfish.jaxb.runtime.api.AccessorException;
import org.glassfish.jaxb.core.v2.ClassFactory;
import org.glassfish.jaxb.core.v2.WellKnownNamespace;
import org.glassfish.jaxb.core.v2.model.core.ID;
import org.glassfish.jaxb.runtime.v2.model.runtime.RuntimeClassInfo;
import org.glassfish.jaxb.runtime.v2.model.runtime.RuntimePropertyInfo;
import org.glassfish.jaxb.runtime.v2.runtime.property.AttributeProperty;
import org.glassfish.jaxb.runtime.v2.runtime.property.Property;
import org.glassfish.jaxb.runtime.v2.runtime.property.PropertyFactory;
import org.glassfish.jaxb.runtime.v2.runtime.reflect.Accessor;
import org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.Loader;
import org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.StructureLoader;
import org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.UnmarshallingContext;
import org.glassfish.jaxb.runtime.v2.runtime.unmarshaller.XsiTypeLoader;
import jakarta.xml.bind.ValidationEvent;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.helpers.ValidationEventImpl;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.LocatorImpl;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
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;

/**
 * {@link JaxBeanInfo} implementation for j2s bean.
 *
 * @author Kohsuke Kawaguchi ([email protected])
 */
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 = org.glassfish.jaxb.core.Utils.getClassLogger(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy