/** * 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.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.XmlElement; import javax.xml.bind.annotation.XmlList; import javax.xml.bind.annotation.XmlTransient; 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.i18n.Message; import org.apache.cxf.common.jaxb.JAXBBeanInfo; import org.apache.cxf.common.jaxb.JAXBContextProxy; import org.apache.cxf.common.jaxb.JAXBUtils; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.common.xmlschema.SchemaCollection; 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.cxf.wsdl.WSDLConstants; 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.XmlSchemaSequence; import org.apache.ws.commons.schema.XmlSchemaSequenceMember; 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; JAXBSchemaInitializer(ServiceInfo serviceInfo, SchemaCollection col, JAXBContext context, boolean q, String defaultNs) { super(serviceInfo); schemas = col; this.context = JAXBUtils.createJAXBContextProxy(context, serviceInfo.getXmlSchemaCollection(), defaultNs); 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; } } } } Annotation[] anns = (Annotation[])part.getProperty("parameter.annotations"); XmlJavaTypeAdapter jta = findFromTypeAdapter(context, clazz, anns); JAXBBeanInfo jtaBeanInfo = null; if (jta != null) { jtaBeanInfo = findFromTypeAdapter(context, jta.value()); } JAXBBeanInfo beanInfo = getBeanInfo(clazz); if (jtaBeanInfo != beanInfo && jta != null) { beanInfo = jtaBeanInfo; 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.getRef().getTarget() != null) { part.setTypeQName(el.getRef().getTargetQName()); } 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(type.getParent(), false); 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); } } } } static XmlJavaTypeAdapter findFromTypeAdapter(JAXBContextProxy context, Class<?> clazz, Annotation[] anns) { JAXBBeanInfo ret = null; if (anns != null) { for (Annotation a : anns) { if (XmlJavaTypeAdapter.class.isAssignableFrom(a.annotationType())) { ret = findFromTypeAdapter(context, ((XmlJavaTypeAdapter)a).value()); if (ret != null) { return (XmlJavaTypeAdapter)a; } } } } if (clazz != null) { XmlJavaTypeAdapter xjta = clazz.getAnnotation(XmlJavaTypeAdapter.class); if (xjta != null) { ret = findFromTypeAdapter(context, xjta.value()); if (ret != null) { return xjta; } } } return null; } static JAXBBeanInfo findFromTypeAdapter(JAXBContextProxy context, @SuppressWarnings("rawtypes") 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(context, (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) { createXsElement(schemaInfo.getSchema(), part, typeName, schemaInfo); } else if (!typeName.equals(el.getSchemaTypeName())) { throw new Fault(new Message("CANNOT_CREATE_ELEMENT", LOG, qn, typeName, el.getSchemaTypeName())); } return; } XmlSchema schema = schemas.newXmlSchemaInCollection(qn.getNamespaceURI()); if (qualifiedSchemas) { schema.setElementFormDefault(XmlSchemaForm.QUALIFIED); } schemaInfo = new SchemaInfo(qn.getNamespaceURI(), qualifiedSchemas, false); schemaInfo.setSchema(schema); el = createXsElement(schema, part, typeName, schemaInfo); 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(XmlSchema schema, MessagePartInfo part, QName typeName, SchemaInfo schemaInfo) { XmlSchemaElement el = new XmlSchemaElement(schema, true); el.setName(part.getElementQName().getLocalPart()); el.setNillable(true); el.setSchemaTypeName(typeName); part.setXmlSchema(el); schemaInfo.setElement(null); return el; } public void end(FaultInfo fault) { MessagePartInfo part = fault.getFirstMessagePart(); 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(schemaInfo.getSchema(), true); el.setName(part.getElementQName().getLocalPart()); el.setNillable(true); 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(schemaInfo.getSchema(), true); el.setName(part.getElementQName().getLocalPart()); schemaInfo.setElement(null); part.setXmlSchema(el); XmlSchemaComplexType ct = new XmlSchemaComplexType(schemaInfo.getSchema(), false); el.setSchemaType(ct); XmlSchemaSequence seq = new XmlSchemaSequence(); ct.setParticle(seq); 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(schemaInfo.getSchema(), false); el.setName(m.getName().substring(beginIdx)); Iterator<QName> itr = beanInfo.getTypeNames().iterator(); if (!itr.hasNext()) { return; } QName typeName = itr.next(); el.setSchemaTypeName(typeName); } seq.getItems().add(el); } catch (Exception e) { //not mappable } } } } } 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; boolean respectXmlTypeNS = false; XmlSchema faultBeanSchema = null; if (xmlTypeAnno != null && !StringUtils.isEmpty(xmlTypeAnno.namespace()) && !xmlTypeAnno.namespace().equals(part.getElementQName().getNamespaceURI())) { respectXmlTypeNS = true; NamespaceMap nsMap = new NamespaceMap(); nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, xmlTypeAnno.namespace()); nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD); SchemaInfo faultBeanSchemaInfo = createSchemaIfNeeded(xmlTypeAnno.namespace(), nsMap); faultBeanSchema = faultBeanSchemaInfo.getSchema(); } if (xmlTypeAnno != null && xmlTypeAnno.propOrder().length > 0) { propertyOrder = xmlTypeAnno.propOrder(); //TODO: handle @XmlAccessOrder } XmlSchema schema = null; if (schemaInfo == null) { NamespaceMap nsMap = new NamespaceMap(); nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, part.getElementQName().getNamespaceURI()); nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD); schemaInfo = createSchemaIfNeeded(part.getElementQName().getNamespaceURI(), nsMap); } schema = schemaInfo.getSchema(); // Before updating everything, make sure we haven't added this // type yet. Multiple methods that throw the same exception // types will cause duplicates. String faultTypeName = xmlTypeAnno != null && !StringUtils.isEmpty(xmlTypeAnno.name()) ? xmlTypeAnno.name() : part.getElementQName().getLocalPart(); XmlSchemaType existingType = schema.getTypeByName(faultTypeName); if (existingType != null) { return; } XmlSchemaElement el = new XmlSchemaElement(schema, true); el.setName(part.getElementQName().getLocalPart()); part.setXmlSchema(el); schemaInfo.setElement(null); if (respectXmlTypeNS) { schema = faultBeanSchema; //create complexType in the new created schema for xmlType } XmlSchemaComplexType ct = new XmlSchemaComplexType(schema, true); ct.setName(faultTypeName); el.setSchemaTypeName(ct.getQName()); XmlSchemaSequence seq = new XmlSchemaSequence(); ct.setParticle(seq); String namespace = part.getElementQName().getNamespaceURI(); XmlAccessType accessType = Utils.getXmlAccessType(cls); // 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, seq, f); } else { JAXBBeanInfo beanInfo = getBeanInfo(type); if (beanInfo != null) { XmlElement xmlElementAnno = f.getAnnotation(XmlElement.class); addElement(schema, seq, beanInfo, new QName(namespace, f.getName()), isArray(type), xmlElementAnno); } } } 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, seq, 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); XmlElement xmlElementAnno = m.getAnnotation(XmlElement.class); addElement(schema, seq, beanInfo, new QName(namespace, name), isArray(type), xmlElementAnno); } } } // Create element in xsd:sequence for Exception.class if (Exception.class.isAssignableFrom(cls)) { addExceptionMessage(cls, schema, seq); } if (propertyOrder != null) { if (propertyOrder.length == seq.getItems().size()) { sortItems(seq, propertyOrder); } else if (propertyOrder.length > 1 || (propertyOrder.length == 1 && !propertyOrder[0].isEmpty())) { 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(seq); } schemas.addCrossImports(); part.setProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION", Boolean.TRUE); } private void addExceptionMessage(Class<?> cls, XmlSchema schema, XmlSchemaSequence seq) { try { //a subclass could mark the message method as transient Method m = cls.getMethod("getMessage"); if (!m.isAnnotationPresent(XmlTransient.class) && m.getDeclaringClass().equals(Throwable.class)) { JAXBBeanInfo beanInfo = getBeanInfo(java.lang.String.class); XmlSchemaElement exEle = new XmlSchemaElement(schema, false); exEle.setName("message"); exEle.setSchemaTypeName(getTypeName(beanInfo)); exEle.setMinOccurs(0); seq.getItems().add(exEle); } } catch (Exception e) { //ignore, just won't have the message element } } 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, XmlSchemaSequence seq, Field f) { XmlSchemaComplexType generics = new XmlSchemaComplexType(schema, true); 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(schema, false); newel.setName(name); newel.setSchemaTypeName(generics.getQName()); newel.setMinOccurs(0); if (!seq.getItems().contains(newel)) { seq.getItems().add(newel); } } private void buildGenericElements(XmlSchema schema, XmlSchemaSequence seq, 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, true); 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(schema, false); newel.setName(name); newel.setSchemaTypeName(generics.getQName()); newel.setMinOccurs(0); if (!seq.getItems().contains(newel)) { seq.getItems().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(schema, false); 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(schema, false); 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; } protected void addElement(XmlSchema schema, XmlSchemaSequence seq, JAXBBeanInfo beanInfo, QName name, boolean isArray, XmlElement xmlElementAnno) { XmlSchemaElement el = new XmlSchemaElement(schema, false); if (isArray) { el.setMinOccurs(0); el.setMaxOccurs(Long.MAX_VALUE); } else { if (xmlElementAnno == null) { el.setMinOccurs(0); el.setNillable(false); } else { el.setNillable(xmlElementAnno.nillable()); int minOccurs = xmlElementAnno.required() ? 1 : 0; el.setMinOccurs(minOccurs); } } if (beanInfo.isElement()) { QName ename = new QName(beanInfo.getElementNamespaceURI(null), beanInfo.getElementLocalName(null)); XmlSchemaElement el2 = schemas.getElementByQName(ename); el.setNillable(false); el.getRef().setTargetQName(el2.getQName()); } else { if (xmlElementAnno != null && !StringUtils.isEmpty(xmlElementAnno.name())) { el.setName(xmlElementAnno.name()); } else { el.setName(name.getLocalPart()); } Iterator<QName> itr = beanInfo.getTypeNames().iterator(); if (!itr.hasNext()) { return; } QName typeName = itr.next(); el.setSchemaTypeName(typeName); } seq.getItems().add(el); } private SchemaInfo createSchemaIfNeeded(String namespace, NamespaceMap nsMap) { SchemaInfo schemaInfo = serviceInfo.getSchema(namespace); if (schemaInfo == null) { XmlSchema xmlSchema = schemas.newXmlSchemaInCollection(namespace); if (qualifiedSchemas) { xmlSchema.setElementFormDefault(XmlSchemaForm.QUALIFIED); } xmlSchema.setNamespaceContext(nsMap); schemaInfo = new SchemaInfo(namespace); schemaInfo.setSchema(xmlSchema); serviceInfo.addSchema(schemaInfo); } return schemaInfo; } private boolean isExistSchemaElement(XmlSchema schema, QName qn) { return schema.getElementByName(qn) != null; } private void sortItems(final XmlSchemaSequence seq, final String[] propertyOrder) { final List<String> propList = Arrays.asList(propertyOrder); Collections.sort(seq.getItems(), new Comparator<XmlSchemaSequenceMember>() { public int compare(XmlSchemaSequenceMember o1, XmlSchemaSequenceMember o2) { XmlSchemaElement element1 = (XmlSchemaElement)o1; XmlSchemaElement element2 = (XmlSchemaElement)o2; int index1 = propList.indexOf(element1.getName()); int index2 = propList.indexOf(element2.getName()); return index1 - index2; } }); } //sort to Alphabetical order private void sort(final XmlSchemaSequence seq) { Collections.sort(seq.getItems(), new Comparator<XmlSchemaSequenceMember>() { public int compare(XmlSchemaSequenceMember o1, XmlSchemaSequenceMember o2) { XmlSchemaElement element1 = (XmlSchemaElement)o1; XmlSchemaElement element2 = (XmlSchemaElement)o2; return element1.getName().compareTo(element2.getName()); } }); } }