blob: dde712fd9b976944f6196a0ef8ba319f476bd814 [file] [log] [blame]
/**
* 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();
}
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());
}
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) {
if (anns != null) {
for (Annotation a : anns) {
if (XmlJavaTypeAdapter.class.isAssignableFrom(a.annotationType())) {
JAXBBeanInfo ret = findFromTypeAdapter(context, ((XmlJavaTypeAdapter)a).value());
if (ret != null) {
return (XmlJavaTypeAdapter)a;
}
}
}
}
if (clazz != null) {
XmlJavaTypeAdapter xjta = clazz.getAnnotation(XmlJavaTypeAdapter.class);
if (xjta != null) {
JAXBBeanInfo 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) {
SchemaInfo schemaInfo = serviceInfo.getSchema(qn.getNamespaceURI());
if (schemaInfo != null) {
XmlSchemaElement 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);
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
}
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);
}
XmlSchema 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());
}
});
}
}