Package org.apache.cxf.jaxb

Source Code of org.apache.cxf.jaxb.JAXBSchemaInitializer

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.cxf.jaxb;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlList;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;

import org.apache.cxf.common.WSDLConstants;
import org.apache.cxf.common.i18n.Message;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.ReflectionInvokationHandler;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.common.xmlschema.SchemaCollection;
import org.apache.cxf.common.xmlschema.XmlSchemaUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.service.ServiceModelVisitor;
import org.apache.cxf.service.model.FaultInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.SchemaInfo;
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaForm;
import org.apache.ws.commons.schema.XmlSchemaObject;
import org.apache.ws.commons.schema.XmlSchemaSequence;
import org.apache.ws.commons.schema.XmlSchemaSimpleType;
import org.apache.ws.commons.schema.XmlSchemaSimpleTypeList;
import org.apache.ws.commons.schema.XmlSchemaType;
import org.apache.ws.commons.schema.utils.NamespaceMap;

/**
* Walks the service model and sets up the element/type names.
*/
class JAXBSchemaInitializer extends ServiceModelVisitor {
    private static final Logger LOG = LogUtils.getLogger(JAXBSchemaInitializer.class);

    private SchemaCollection schemas;
    private JAXBContextProxy context;
    private final boolean qualifiedSchemas;
   
    public JAXBSchemaInitializer(ServiceInfo serviceInfo,
                                 SchemaCollection col,
                                 JAXBContext context,
                                 boolean q) {
        super(serviceInfo);
        schemas = col;
        this.context = ReflectionInvokationHandler.createProxyWrapper(context, JAXBContextProxy.class);
        this.qualifiedSchemas = q;
    }

    static Class<?> getArrayComponentType(Type cls) {
        if (cls instanceof Class) {
            if (((Class)cls).isArray()) {
                return ((Class)cls).getComponentType();
            } else {
                return (Class)cls;
            }
        } else if (cls instanceof ParameterizedType) {
            for (Type t2 : ((ParameterizedType)cls).getActualTypeArguments()) {
                return getArrayComponentType(t2);
            }
        } else if (cls instanceof GenericArrayType) {
            GenericArrayType gt = (GenericArrayType)cls;
            Class ct = (Class) gt.getGenericComponentType();
            return Array.newInstance(ct, 0).getClass();
        }
        return null;
    }
   
    public JAXBBeanInfo getBeanInfo(Type cls) {
        if (cls instanceof Class) {
            if (((Class)cls).isArray()) {
                return getBeanInfo(((Class)cls).getComponentType());
            } else {
                return getBeanInfo((Class)cls);
            }
        } else if (cls instanceof ParameterizedType) {
            for (Type t2 : ((ParameterizedType)cls).getActualTypeArguments()) {
                return getBeanInfo(t2);
            }
        } else if (cls instanceof GenericArrayType) {
            GenericArrayType gt = (GenericArrayType)cls;
            Class ct = (Class) gt.getGenericComponentType();
            ct = Array.newInstance(ct, 0).getClass();

            return getBeanInfo(ct);
        }
       
        return null;
    }
   
    public JAXBBeanInfo getBeanInfo(Class<?> cls) {
        return getBeanInfo(context, cls);
    }
   
    public static JAXBBeanInfo getBeanInfo(JAXBContextProxy context, Class<?> cls) {
        return JAXBUtils.getBeanInfo(context, cls);
    }
   
    @Override
    public void begin(MessagePartInfo part) {
        // Check to see if the WSDL information has been filled in for us.
        if (part.getTypeQName() != null || part.getElementQName() != null) {
            checkForExistence(part);
            return;
        }
       
        Class<?> clazz = part.getTypeClass();
        if (clazz == null) {
            return;
        }

        boolean isFromWrapper = part.getMessageInfo().getOperation().isUnwrapped();
        boolean isList = false;
        if (clazz.isArray()) {
            if (isFromWrapper && !Byte.TYPE.equals(clazz.getComponentType())) {
                clazz = clazz.getComponentType();
            } else if (!isFromWrapper) {
                Annotation[] anns = (Annotation[])part.getProperty("parameter.annotations");
                for (Annotation a : anns) {
                    if (a instanceof XmlList) {
                        part.setProperty("honor.jaxb.annotations", Boolean.TRUE);
                        clazz = clazz.getComponentType();
                        isList = true;
                    }
                }
            }
        }

        JAXBBeanInfo beanInfo = getBeanInfo(clazz);
        if (beanInfo == null) {
            Annotation[] anns = (Annotation[])part.getProperty("parameter.annotations");
            XmlJavaTypeAdapter jta = findFromTypeAdapter(clazz, anns);
            if (jta != null) {
                beanInfo = findFromTypeAdapter(jta.value());
                if (anns == null) {
                    anns = new Annotation[] {jta};
                } else {
                    boolean found = false;
                    for (Annotation t : anns) {
                        if (t == jta) {
                            found = true;
                        }
                    }
                    if (!found) {
                        Annotation tmp[] = new Annotation[anns.length + 1];
                        System.arraycopy(anns, 0, tmp, 0, anns.length);
                        tmp[anns.length] = jta;
                        anns = tmp;
                    }
                }
                part.setProperty("parameter.annotations", anns);
                part.setProperty("honor.jaxb.annotations", Boolean.TRUE);
            }
        }
        if (beanInfo == null) {
            if (Exception.class.isAssignableFrom(clazz)) {
                QName name = (QName)part.getMessageInfo().getProperty("elementName");
                part.setElementQName(name);
                buildExceptionType(part, clazz);
            }
            return;
        }
        boolean isElement = beanInfo.isElement()
            && !Boolean.TRUE.equals(part.getMessageInfo().getOperation()
                                        .getProperty("operation.force.types"));
        boolean hasType = !beanInfo.getTypeNames().isEmpty();
        if (isElement && isFromWrapper && hasType) {
            //if there is both a Global element and a global type, AND we are in a wrapper,
            //make sure we use the type instead of a ref to the element to
            //match the rules for wrapped/unwrapped
            isElement = false;
        }

        part.setElement(isElement);
       
        if (isElement) {
            QName name = new QName(beanInfo.getElementNamespaceURI(null),
                                   beanInfo.getElementLocalName(null));
            XmlSchemaElement el = schemas.getElementByQName(name);
            if (el != null && el.getRefName() != null) {
                part.setTypeQName(el.getRefName());
            } else {
                part.setElementQName(name);
            }
            part.setXmlSchema(el);
        } else  {
            QName typeName = getTypeName(beanInfo);
            if (typeName != null) {
                XmlSchemaType type = schemas.getTypeByQName(typeName);
                if  (isList && type instanceof XmlSchemaSimpleType) {
                    XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType(null);
                    XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
                    XmlSchemaSimpleType stype = (XmlSchemaSimpleType)type;
                    list.setItemTypeName(stype.getQName());
                    simpleType.setContent(list);
                    part.setXmlSchema(simpleType);
                    if (part.getConcreteName() == null) {
                        part.setConcreteName(new QName(null, part.getName().getLocalPart()));
                    }
                } else {
                    part.setTypeQName(typeName);
                    part.setXmlSchema(type);
                }
            }
        }
    }

    private XmlJavaTypeAdapter findFromTypeAdapter(Class<?> clazz, Annotation[] anns) {
        JAXBBeanInfo ret = null;
        if (anns != null) {
            for (Annotation a : anns) {
                if (XmlJavaTypeAdapter.class.isAssignableFrom(a.annotationType())) {
                    ret = findFromTypeAdapter(((XmlJavaTypeAdapter)a).value());
                    if (ret != null) {
                        return (XmlJavaTypeAdapter)a;
                    }
                }
            }
        }
        XmlJavaTypeAdapter xjta = clazz.getAnnotation(XmlJavaTypeAdapter.class);
        if (xjta != null) {
            ret = findFromTypeAdapter(xjta.value());
            if (ret != null) {
                return xjta;
            }
        }
        return null;
    }

    private JAXBBeanInfo findFromTypeAdapter(Class<? extends XmlAdapter> aclass) {
        Class<?> c2 = aclass;
        Type sp = c2.getGenericSuperclass();
        while (!XmlAdapter.class.equals(c2) && c2 != null) {
            sp = c2.getGenericSuperclass();
            c2 = c2.getSuperclass();
        }
        if (sp instanceof ParameterizedType) {
            Type tp = ((ParameterizedType)sp).getActualTypeArguments()[0];
            if (tp instanceof Class) {
                return getBeanInfo((Class<?>)tp);
            }
        }
        return null;
    }

    private QName getTypeName(JAXBBeanInfo beanInfo) {
        Iterator<QName> itr = beanInfo.getTypeNames().iterator();
        if (!itr.hasNext()) {
            return null;
        }
       
        return itr.next();
    }
    public void checkForExistence(MessagePartInfo part) {
        QName qn = part.getElementQName();
        if (qn != null) {
            XmlSchemaElement el = schemas.getElementByQName(qn);
            if (el == null) {
                Class<?> clazz = part.getTypeClass();
                if (clazz == null) {
                    return;
                }

                boolean isFromWrapper = part.getMessageInfo().getOperation().isUnwrapped();
                if (isFromWrapper && clazz.isArray() && !Byte.TYPE.equals(clazz.getComponentType())) {
                    clazz = clazz.getComponentType();
                }
                JAXBBeanInfo beanInfo = getBeanInfo(clazz);
                if (beanInfo == null) {
                    if (Exception.class.isAssignableFrom(clazz)) {
                        QName name = (QName)part.getMessageInfo().getProperty("elementName");
                        part.setElementQName(name);
                        buildExceptionType(part, clazz);
                    }
                    return;
                }
               
                QName typeName = getTypeName(beanInfo);

                createBridgeXsElement(part, qn, typeName);
            } else if (part.getXmlSchema() == null) {
                part.setXmlSchema(el);
            }
        }
    }

    private void createBridgeXsElement(MessagePartInfo part, QName qn, QName typeName) {
        XmlSchemaElement el = null;
        SchemaInfo schemaInfo = serviceInfo.getSchema(qn.getNamespaceURI());
        if (schemaInfo != null) {
            el = schemaInfo.getElementByQName(qn);
            if (el == null) {
                el = createXsElement(part, typeName, schemaInfo);

                schemaInfo.getSchema().getElements().add(el.getQName(), el);
                schemaInfo.getSchema().getItems().add(el);
            } else if (!typeName.equals(el.getSchemaTypeName())) {
                throw new Fault(new Message("CANNOT_CREATE_ELEMENT", LOG,
                                            qn, typeName, el.getSchemaTypeName()));
            }
            return;
        }
       
        schemaInfo = new SchemaInfo(qn.getNamespaceURI(), qualifiedSchemas, false);
       
        el = createXsElement(part, typeName, schemaInfo);

        XmlSchema schema = schemas.newXmlSchemaInCollection(qn.getNamespaceURI());
        if (qualifiedSchemas) {
            schema.setElementFormDefault(new XmlSchemaForm(XmlSchemaForm.QUALIFIED));
        }
        schemaInfo.setSchema(schema);
        schema.getElements().add(el.getQName(), el);
        schema.getItems().add(el);

        NamespaceMap nsMap = new NamespaceMap();
        nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, schema.getTargetNamespace());
        nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD);
        schema.setNamespaceContext(nsMap);
       
        serviceInfo.addSchema(schemaInfo);
    }

    private XmlSchemaElement createXsElement(MessagePartInfo part, QName typeName, SchemaInfo schemaInfo) {
        XmlSchemaElement el = new XmlSchemaElement();
        XmlSchemaUtils.setElementQName(el, part.getElementQName());
        el.setNillable(true);
        el.setSchemaTypeName(typeName);
        part.setXmlSchema(el);
        schemaInfo.setElement(null);
        return el;
    }
   
    public void end(FaultInfo fault) {
        MessagePartInfo part = fault.getMessageParts().get(0);
        Class<?> cls = part.getTypeClass();
        Class<?> cl2 = (Class)fault.getProperty(Class.class.getName());
        if (cls != cl2) {
            QName name = (QName)fault.getProperty("elementName");
            part.setElementQName(name);          
            JAXBBeanInfo beanInfo = getBeanInfo(cls);
            if (beanInfo == null) {
                throw new Fault(new Message("NO_BEAN_INFO", LOG, cls.getName()));
            }
            SchemaInfo schemaInfo = serviceInfo.getSchema(part.getElementQName().getNamespaceURI());
            if (schemaInfo != null
                && !isExistSchemaElement(schemaInfo.getSchema(), part.getElementQName())) {
               
                XmlSchemaElement el = new XmlSchemaElement();
                XmlSchemaUtils.setElementQName(el, part.getElementQName());
                el.setNillable(true);
               
                schemaInfo.getSchema().getItems().add(el);
                schemaInfo.getSchema().getElements().add(el.getQName(), el);
                schemaInfo.setElement(null);

                Iterator<QName> itr = beanInfo.getTypeNames().iterator();
                if (!itr.hasNext()) {
                    return;
                }
                QName typeName = itr.next();
                el.setSchemaTypeName(typeName);
            }
        } else if (part.getXmlSchema() == null) {
            try {
                cls.getConstructor(new Class[] {String.class});
            } catch (Exception e) {
                try {
                    cls.getConstructor(new Class[0]);
                } catch (Exception e2) {
                    //no String or default constructor, we cannot use it
                    return;
                }
            }           
           
            //not mappable in JAXBContext directly, we'll have to do it manually :-(
            SchemaInfo schemaInfo = serviceInfo.getSchema(part.getElementQName().getNamespaceURI());
            if (schemaInfo == null
                || isExistSchemaElement(schemaInfo.getSchema(), part.getElementQName())) {
                return;
            }
               
            XmlSchemaElement el = new XmlSchemaElement();
            XmlSchemaUtils.setElementQName(el, part.getElementQName());
           
            schemaInfo.getSchema().getItems().add(el);
            schemaInfo.getSchema().getElements().add(el.getQName(), el);
            schemaInfo.setElement(null);

            part.setXmlSchema(el);

            XmlSchemaComplexType ct = new XmlSchemaComplexType(schemaInfo.getSchema());
            el.setSchemaType(ct);
            XmlSchemaSequence seq = new XmlSchemaSequence();
            ct.setParticle(seq);
               
            List<XmlSchemaElement> elementList = new ArrayList<XmlSchemaElement>();

            Method methods[] = cls.getMethods();
            for (Method m : methods) {
                if (m.getName().startsWith("get")
                    || m.getName().startsWith("is")) {
                    int beginIdx = m.getName().startsWith("get") ? 3 : 2;
                    try {
                        m.getDeclaringClass().getMethod("set" + m.getName().substring(beginIdx),
                                                        m.getReturnType());
                       
                        JAXBBeanInfo beanInfo = getBeanInfo(m.getReturnType());
                        if (beanInfo != null) {
                            el = new XmlSchemaElement();
                            el.setName(m.getName().substring(beginIdx));
                           
                            String ns = schemaInfo.getSchema().getElementFormDefault()
                                .getValue().equals(XmlSchemaForm.UNQUALIFIED)
                                ? "" : part.getElementQName().getLocalPart();
                            XmlSchemaUtils.setElementQName(el,
                                                           new QName(ns, m.getName().substring(beginIdx)));
                            Iterator<QName> itr = beanInfo.getTypeNames().iterator();
                            if (!itr.hasNext()) {
                                return;
                            }
                            QName typeName = itr.next();
                            el.setSchemaTypeName(typeName);
                        }
                       
                        elementList.add(el);
                    } catch (Exception e) {
                        //not mappable
                    }
                }
            }
            XmlAccessorOrder xmlAccessorOrder = cls.getAnnotation(XmlAccessorOrder.class);
            XmlType xmlTypeAnno = cls.getAnnotation(XmlType.class);
            String[] propertyOrder = null;

            if (xmlTypeAnno != null &&  xmlTypeAnno.propOrder().length > 0) {
                propertyOrder = xmlTypeAnno.propOrder();
                //TODO: handle @XmlAccessOrder
            }

            if (propertyOrder != null && propertyOrder.length == elementList.size()) {
                sortItems(elementList, propertyOrder);
            } else if (propertyOrder != null && propertyOrder.length != elementList.size()) {
                LOG.log(Level.WARNING, "propOrder in @XmlType doesn't define all schema elements: "
                    + Arrays.toString(propertyOrder));
            }
       
            if (xmlAccessorOrder != null && xmlAccessorOrder.value().equals(XmlAccessOrder.ALPHABETICAL)
                && propertyOrder == null) {
                sort(elementList);
            }

            for (XmlSchemaElement elem : elementList) {
                seq.getItems().add(elem);
            }
        }
    }
   
    private void buildExceptionType(MessagePartInfo part, Class<?> cls) {
        SchemaInfo schemaInfo = null;
        for (SchemaInfo s : serviceInfo.getSchemas()) {
            if (s.getNamespaceURI().equals(part.getElementQName().getNamespaceURI())) {
                schemaInfo = s;               
                break;
            }
        }
        XmlAccessorOrder xmlAccessorOrder = cls.getAnnotation(XmlAccessorOrder.class);
        XmlType xmlTypeAnno = cls.getAnnotation(XmlType.class);
        String[] propertyOrder = null;

        if (xmlTypeAnno != null &&  xmlTypeAnno.propOrder().length > 0) {
            propertyOrder = xmlTypeAnno.propOrder();
            //TODO: handle @XmlAccessOrder
        }

        XmlSchema schema;
        if (schemaInfo == null) {
            schema = schemas.newXmlSchemaInCollection(part.getElementQName().getNamespaceURI());

            if (qualifiedSchemas) {
                schema.setElementFormDefault(new XmlSchemaForm(XmlSchemaForm.QUALIFIED));
            }

            NamespaceMap nsMap = new NamespaceMap();
            nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, schema.getTargetNamespace());
            nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD);
            schema.setNamespaceContext(nsMap);

           
            schemaInfo = new SchemaInfo(part.getElementQName().getNamespaceURI());
            schemaInfo.setSchema(schema);
            serviceInfo.addSchema(schemaInfo);
        } else {
            schema = schemaInfo.getSchema();
        }
       
        XmlSchemaComplexType ct = new XmlSchemaComplexType(schema);
        ct.setName(part.getElementQName().getLocalPart());
        // Before updating everything, make sure we haven't added this
        // type yet.  Multiple methods that throw the same exception
        // types will cause duplicates.
        if (schema.getTypeByName(ct.getQName()) != null) {
            return;
        }
       
        XmlSchemaElement el = new XmlSchemaElement();
        XmlSchemaUtils.setElementQName(el, part.getElementQName());
        schema.getItems().add(el);
        schema.getElements().add(el.getQName(), el);
        part.setXmlSchema(el);
       
        schema.getItems().add(ct);
        schema.addType(ct);
        schemaInfo.setElement(null);
        el.setSchemaTypeName(part.getElementQName());
       
        XmlSchemaSequence seq = new XmlSchemaSequence();
        ct.setParticle(seq);
        String namespace = part.getElementQName().getNamespaceURI();
       
        XmlAccessorType accessorType = cls.getAnnotation(XmlAccessorType.class);
        if (accessorType == null && cls.getPackage() != null) {
            accessorType = cls.getPackage().getAnnotation(XmlAccessorType.class);
        }

        XmlAccessType accessType = Utils.getXmlAccessType(cls);

        List<XmlSchemaElement> elementList = new ArrayList<XmlSchemaElement>();

        for (Field f : Utils.getFields(cls, accessType)) {
            //map field
            Type type = Utils.getFieldType(f);
            //we want to return the right type for collections so if we get null
            //from the return type we check if it's ParameterizedType and get the
            //generic return type.
            if ((type == null) && (f.getGenericType() instanceof ParameterizedType)) {
                type = f.getGenericType();
            }
            if (generateGenericType(type)) {
                buildGenericElements(schema, elementList, f);
            } else {
                JAXBBeanInfo beanInfo = getBeanInfo(type);
                if (beanInfo != null) {
                    addElement(elementList, beanInfo, new QName(namespace, f.getName()), isArray(type));
                }
            }               
        }
        for (Method m : Utils.getGetters(cls, accessType)) {
            //map method
            Type type = Utils.getMethodReturnType(m);
            //we want to return the right type for collections so if we get null
            //from the return type we check if it's ParameterizedType and get the
            //generic return type.
            if ((type == null) && (m.getGenericReturnType() instanceof ParameterizedType)) {
                type = m.getGenericReturnType();
            }
           
            if (generateGenericType(type)) {
                buildGenericElements(schema, elementList, m, type);
            } else {
                JAXBBeanInfo beanInfo = getBeanInfo(type);
                if (beanInfo != null) {
                    int idx = m.getName().startsWith("get") ? 3 : 2;
                    String name = m.getName().substring(idx);
                    name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
                    addElement(elementList, beanInfo, new QName(namespace, name), isArray(type));
                }
            }
        }

        if (propertyOrder != null && propertyOrder.length == elementList.size()) {
            sortItems(elementList, propertyOrder);
        } else if (propertyOrder != null && propertyOrder.length != elementList.size()) {
            LOG.log(Level.WARNING, "propOrder in @XmlType doesn't define all schema elements: "
                + Arrays.toString(propertyOrder));
        }
       
        if (xmlAccessorOrder != null && xmlAccessorOrder.value().equals(XmlAccessOrder.ALPHABETICAL)
            && propertyOrder == null) {
            sort(elementList);
        }

        for (XmlSchemaElement elem : elementList) {
            seq.getItems().add(elem);
        }

        part.setProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION", Boolean.TRUE);
    }
   
    private boolean generateGenericType(Type type) {
        if (type instanceof ParameterizedType) {
            ParameterizedType paramType = (ParameterizedType)type;
            if (paramType.getActualTypeArguments().length > 1) {
                return true;

            }
        }
        return false;
    }
   
    private void buildGenericElements(XmlSchema schema, List<XmlSchemaElement> elementList, Field f) {
        XmlSchemaComplexType generics = new XmlSchemaComplexType(schema);
        Type type = f.getGenericType();
        String rawType = ((ParameterizedType)type).getRawType().toString();
        String typeName = StringUtils.uncapitalize(rawType.substring(rawType.lastIndexOf(".") + 1));
        generics.setName(typeName);

        Class<?> genericsClass = f.getType();
        buildGenericSeq(schema, generics, genericsClass);  

        String name = Character.toLowerCase(f.getName().charAt(0)) + f.getName().substring(1);
        XmlSchemaElement newel = new XmlSchemaElement();
        newel.setName(name);
        newel.setSchemaTypeName(generics.getQName());
        newel.setMinOccurs(0);
        elementList.add(newel);
    }
    
    private void buildGenericElements(XmlSchema schema,
        List<XmlSchemaElement> elementList, Method m, Type type) {      
        String rawType = ((ParameterizedType)type).getRawType().toString();
        String typeName = StringUtils.uncapitalize(rawType.substring(rawType.lastIndexOf(".") + 1));
       
        XmlSchemaComplexType generics = (XmlSchemaComplexType)schema.getTypeByName(typeName);       
        if (generics == null) {
            generics =  new XmlSchemaComplexType(schema);
            generics.setName(typeName);
        }
       
        Class<?> genericsClass = m.getReturnType();
        buildGenericSeq(schema, generics, genericsClass)
         
        int idx = m.getName().startsWith("get") ? 3 : 2;
        String name = m.getName().substring(idx);
        name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
        XmlSchemaElement newel = new XmlSchemaElement();
        newel.setName(name);
        newel.setSchemaTypeName(generics.getQName());
        newel.setMinOccurs(0);
        elementList.add(newel);
    }
   
    private void buildGenericSeq(XmlSchema schema, XmlSchemaComplexType generics, Class<?> genericsClass) {
        XmlSchemaSequence genericsSeq = new XmlSchemaSequence();
        generics.setParticle(genericsSeq);
        XmlAccessType  accessType = Utils.getXmlAccessType(genericsClass);
       
        for (Field f : Utils.getFields(genericsClass, accessType)) {
            if (f.getGenericType() instanceof TypeVariable) {              
                String genericName = Character.toLowerCase(f.getName().charAt(0)) + f.getName().substring(1);
                XmlSchemaElement genericEle = new XmlSchemaElement();
                genericEle.setName(genericName);
                genericEle.setMinOccurs(0);
                JAXBBeanInfo anyBean = getBeanInfo(context, f.getType());
                Iterator<QName> itr = anyBean.getTypeNames().iterator();
                if (!itr.hasNext()) {
                    return;
                }
                QName typeName = itr.next();
                genericEle.setSchemaTypeName(typeName);
                genericsSeq.getItems().add(genericEle);
            }
        }
              
        for (Method genericMethod : Utils.getGetters(genericsClass, accessType)) {
            if (genericMethod.getGenericReturnType() instanceof TypeVariable) {
                int idx = genericMethod.getName().startsWith("get") ? 3 : 2;
                String genericName = genericMethod.getName().substring(idx);
                genericName = Character.toLowerCase(genericName.charAt(0)) + genericName.substring(1);
                XmlSchemaElement genericEle = new XmlSchemaElement();
                genericEle.setName(genericName);
                genericEle.setMinOccurs(0);
                JAXBBeanInfo anyBean = getBeanInfo(context, genericMethod.getReturnType());
                Iterator<QName> itr = anyBean.getTypeNames().iterator();
                if (!itr.hasNext()) {
                    return;
                }
                QName typeName = itr.next();
                genericEle.setSchemaTypeName(typeName);
                genericsSeq.getItems().add(genericEle);
            }
           
        }
    }
   
    static boolean isArray(Type cls) {
        if (cls instanceof Class) {
            return ((Class)cls).isArray();
        } else if (cls instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType)cls;
            return pt.getActualTypeArguments().length == 1
                && pt.getRawType() instanceof Class
                && Collection.class.isAssignableFrom((Class<?>)pt.getRawType());
        } else if (cls instanceof GenericArrayType) {
            return true;
        }
        return false;
    }

    public void addElement(List<XmlSchemaElement> elementList, JAXBBeanInfo beanInfo,
                           QName name, boolean isArray) {   
        XmlSchemaElement el = new XmlSchemaElement();
        el.setName(name.getLocalPart());
        XmlSchemaUtils.setElementQName(el, name);

        if (isArray) {
            el.setMinOccurs(0);
            el.setMaxOccurs(Long.MAX_VALUE);
        } else {
            el.setMinOccurs(1);
            el.setMaxOccurs(1);
            el.setNillable(true);
        }

        if (beanInfo.isElement()) {
            QName ename = new QName(beanInfo.getElementNamespaceURI(null),
                                   beanInfo.getElementLocalName(null));
            XmlSchemaElement el2 = schemas.getElementByQName(ename);
            XmlSchemaUtils.setElementQName(el, null);
            XmlSchemaUtils.setElementRefName(el, el2.getRefName());
        } else {
            Iterator<QName> itr = beanInfo.getTypeNames().iterator();
            if (!itr.hasNext()) {
                return;
            }
            QName typeName = itr.next();
            el.setSchemaTypeName(typeName);
        }
       
        elementList.add(el);
    }
   
   
    private boolean isExistSchemaElement(XmlSchema schema, QName qn) {
        boolean isExist = false;
        for (Iterator ite = schema.getItems().getIterator(); ite.hasNext();) {
            XmlSchemaObject obj = (XmlSchemaObject)ite.next();
            if (obj instanceof XmlSchemaElement) {
                XmlSchemaElement xsEle = (XmlSchemaElement)obj;
                if (xsEle.getQName().equals(qn)) {
                    isExist = true;
                    break;
                }
            }
        }
        return isExist;
    }
   
    //sort to Alphabetical order
    private void sort(final List<XmlSchemaElement> elementList) {
        Collections.sort(elementList, new Comparator<XmlSchemaElement>() {
            public int compare(XmlSchemaElement e1, XmlSchemaElement e2) {
                return e1.getName().compareTo(e2.getName());
            }
        });
    }
   
    private void sortItems(List<XmlSchemaElement> elementList, String[] propOrder) {
        final List<String> propList = Arrays.asList(propOrder);

        Collections.sort(elementList, new Comparator<XmlSchemaElement>() {
            public int compare(XmlSchemaElement el1, XmlSchemaElement el2) {
                int index1 = propList.indexOf(el1.getName());
                int index2 = propList.indexOf(el2.getName());
                return index1 - index2;
            }
        });
    }
}
TOP

Related Classes of org.apache.cxf.jaxb.JAXBSchemaInitializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.