package at.ac.tuwien.infosys.jaxb;
import java.io.ByteArrayInputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.annotation.AnnotationLocation;
import javax.xml.bind.annotation.AppInfo;
import javax.xml.bind.annotation.Assert;
import javax.xml.bind.annotation.Attribute;
import javax.xml.bind.annotation.Documentation;
import javax.xml.bind.annotation.Facets;
import javax.xml.bind.annotation.Facets.FacetDefinition;
import javax.xml.bind.annotation.Facets.WhiteSpace;
import javax.xml.bind.annotation.MaxOccurs;
import javax.xml.bind.annotation.MinOccurs;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import at.ac.tuwien.infosys.jaxb.AnnotationUtils.AnnotationInvocationHandler;
import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.xml.bind.v2.model.core.ArrayInfo;
import com.sun.xml.bind.v2.model.core.AttributePropertyInfo;
import com.sun.xml.bind.v2.model.core.ClassInfo;
import com.sun.xml.bind.v2.model.core.ElementPropertyInfo;
import com.sun.xml.bind.v2.model.core.EnumConstant;
import com.sun.xml.bind.v2.model.core.EnumLeafInfo;
import com.sun.xml.bind.v2.model.core.ID;
import com.sun.xml.bind.v2.model.core.PropertyInfo;
import com.sun.xml.bind.v2.model.core.TypeRef;
import com.sun.xml.bind.v2.model.core.ValuePropertyInfo;
import com.sun.xml.bind.v2.schemagen.xmlschema.LocalAttribute;
import com.sun.xml.bind.v2.schemagen.xmlschema.LocalElement;
import com.sun.xml.bind.v2.schemagen.xmlschema.Particle;
import com.sun.xml.bind.v2.schemagen.xmlschema.SimpleRestrictionModel;
import com.sun.xml.txw2.TypedXmlWriter;
import com.sun.xml.txw2.output.ResultFactory;
import com.sun.xml.txw2.output.TXWResult;
import com.sun.xml.txw2.output.TXWSerializer;
/**
* @author Waldemar Hummer (hummer@infosys.tuwien.ac.at)
* @version 0.2 added support for Facet restrictions for XML attributes
* @version 0.3 fixed classloading/proxying issue for JBoss, related to:
* http://lists.jboss.org/pipermail/forge-issues/2011-October/000351.html
*/
@SuppressWarnings("all")
public class XmlSchemaEnhancer {
public static final String NS_XSD = "http://www.w3.org/2001/XMLSchema";
public static final String NS_XML = "http://www.w3.org/XML/1998/namespace";
private static ValidationFacetsFilter facetFilter = new ValidationFacetsFilter();
private static final DocumentBuilderFactory XML_FACTORY = DocumentBuilderFactory.newInstance();
private static final List<Class<? extends Annotation>> EXT_ANNO_CLASSES_AT_START =
new ArrayList<Class<? extends Annotation>>();
private static final List<Class<? extends Annotation>> EXT_ANNO_CLASSES_AT_END =
new ArrayList<Class<? extends Annotation>>();
static {
EXT_ANNO_CLASSES_AT_START.add(javax.xml.bind.annotation.Annotation.class);
EXT_ANNO_CLASSES_AT_END.add(Assert.class);
}
public static final AtomicBoolean XSD_11_ENABLED = new AtomicBoolean(true);
public static final Logger logger = Logger
.getLogger(XmlSchemaEnhancer.class.getName());
public static <T, C> boolean hasExtendedAnnotations(TypeRef<T, C> t) {
return hasFacets(t) || hasXsdExtensions(t);
}
public static <T, C> boolean hasExtendedAnnotations(
AttributePropertyInfo<T, C> info) {
return hasFacets(info) || hasXsdExtensions(info);
}
public static <T, C> void addFacets(ValuePropertyInfo<T, C> vp,
SimpleRestrictionModel restriction) {
if (!hasFacets(vp))
return;
Facets facetsAnno = getFacetsAnnotation(vp);
addFacets(facetsAnno, restriction, vp.getSource().getSchemaType());
}
public static <T, C> void addFacets(EnumLeafInfo<T, C> e,
SimpleRestrictionModel restriction) {
T type = e.getType();
if(type instanceof Class<?>) {
Facets facets = ((Class<?>)type).getAnnotation(Facets.class);
addFacets(facets, (TypedXmlWriter)restriction, (Class<?>)type);
} else if(type.getClass().getName().endsWith("ClassType")) {
Facets facets = SchemagenUtil.extractAnnotation(type, Facets.class);
addFacets(facets, (TypedXmlWriter)restriction, (Class<?>)null);
}
}
public static <T, C> void addFacets(TypeRef<T, C> t, LocalElement e) {
if (!hasFacets(t))
return;
Facets facetsAnno = getFacetsAnnotation(t);
TypedXmlWriter restriction = getRestriction(t, e, null);
if(t.getTarget().getType() instanceof Class<?>) {
addFacets(facetsAnno, restriction, (Class<?>)t.getTarget().getType());
} else if(t.getTarget().getType() instanceof ClassType) {
ClassType ct = (ClassType)t.getTarget().getType();
addFacets(facetsAnno, restriction, (Class<?>)null);
}
}
public static <T, C> void addFacets(AttributePropertyInfo<T, C> info,
LocalAttribute attr) {
if (!hasFacets(info))
return;
Facets facetsAnno = getFacetsAnnotation(info);
TypedXmlWriter restriction = getRestriction(info, attr, null);
addFacets(facetsAnno, restriction, info.getSource().getSchemaType());
}
public static <T, C> void addFacets(Facets facetsAnno,
TypedXmlWriter restriction, QName baseType) {
addFacets(facetsAnno, restriction, baseType == null ? null :
Constants.FACET_TYPES.get(baseType.getLocalPart()));
}
public static <T, C> void addFacets(Facets facetsAnno,
TypedXmlWriter restriction, Class<?> baseType) {
Map<String, List<String>> facets = null;
try {
facets = getDefinedFacets(facetsAnno);
} catch (Exception ex) {
logger.log(Level.WARNING,
"Unable to add XSD Facets in Schema generated by JAXB.", ex);
return;
}
/* check if we have invalid facets, e.g., minExclusive on xs:string is not allowed */
checkFacetsValidity(baseType, facets);
for (String facetName : facets.keySet()) {
for (String facetValue : facets.get(facetName)) {
logger.fine("Adding XSD-Facets schema restriction: "
+ new QName(NS_XSD, facetName));
restriction._element(new QName(NS_XSD, facetName),
TypedXmlWriter.class)._attribute("value", facetValue);
}
}
}
private static void checkFacetsValidity(Class<?> baseType,
Map<String, List<String>> facets) {
if(baseType == null)
return;
Set<String> allowed = Constants.FACETS_BY_TYPE.get(baseType);
if(allowed == null && Enum.class.isAssignableFrom(baseType)) {
allowed = Constants.FACETS_BY_TYPE.get(Enum.class);
}
if(allowed == null) {
logger.fine("Cannot determine allowed facets for base type " + baseType);
} else {
for (String facetName : facets.keySet()) {
if(!allowed.contains(facetName)) {
logger.info("Facet '" + facetName + "' not in allowed facets " +
allowed + " for base type " + baseType);
}
}
}
}
public static <T, C> boolean hasFacets(ValuePropertyInfo<T, C> vp) {
Facets facets = getFacetsAnnotation(vp);
return hasFacets(facets);
}
public static <T, C> boolean hasFacets(TypeRef<T, C> t) {
Facets facets = getFacetsAnnotation(t);
return hasFacets(facets);
}
public static <T, C> boolean hasFacets(AttributePropertyInfo<T, C> ap) {
Facets facets = getFacetsAnnotation(ap);
return hasFacets(facets);
}
public static <T, C> boolean hasFacets(Facets facets) {
if (facets == null)
return false;
try {
Map<String, List<String>> definedFacets = getDefinedFacets(facets);
return definedFacets.size() > 0;
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to get defined XSD Facets", e);
return false;
}
}
public static <T, C> void addXsdExtensions(Set<ClassInfo<T, C>> classes,
Set<EnumLeafInfo<T, C>> enums, Set<ArrayInfo<T, C>> arrays,
TypedXmlWriter w) {
Set<Package> annotatedPackages = new HashSet<Package>();
for (ClassInfo<T, C> c : classes) {
annotatedPackages.addAll(extractPackage(c.getType()));
}
for (EnumLeafInfo<T, C> c : enums) {
annotatedPackages.addAll(extractPackage(c.getType()));
}
for (ArrayInfo<T, C> c : arrays) {
annotatedPackages.addAll(extractPackage(c.getType()));
}
for (Package p : annotatedPackages) {
XmlSchemaEnhancer.addXsdExtensionsAtStart(p, w);
}
}
public static <T> void addXsdExtensionsAtStart(T type, TypedXmlWriter w) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(type, c)) {
Annotation anno = getXsdExtensionAnnotation(type, c);
addXsdExtensionInsideElement(anno, w);
}
}
}
public static <T, C> void addXsdExtensionsAtStart(ClassInfo<T, C> ci,
TypedXmlWriter w) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(ci, c)) {
Annotation anno = getXsdExtensionAnnotation(ci, c);
addXsdExtensionInsideElement(anno, w);
}
}
}
public static <T, C> void addXsdExtensionsAtStart(
AttributePropertyInfo<T, C> _info, LocalAttribute _attr) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(_info, c)) {
Annotation anno = getXsdExtensionAnnotation(_info, c);
addXsdExtensionInsideElement(anno, _attr);
}
}
}
public static <T, C> void addXsdExtensionsAtStart(TypeRef<T, C> t, LocalElement e) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(t, c)) {
Annotation anno = getXsdExtensionAnnotation(t, c);
addXsdExtensionInsideElement(anno, e);
}
}
}
public static <T,C> void addXsdExtensionsAtEnd(ClassInfo<T,C> type, TypedXmlWriter w) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_END) {
if(hasXsdExtension(type, c)) {
Annotation anno = getXsdExtensionAnnotation(type, c);
addXsdExtensionInsideElement(anno, w);
}
}
}
public static <T,C> void addXsdExtensionsAtEnd(PropertyInfo<T, C> elementInfo, TypedXmlWriter w) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_END) {
Annotation anno = elementInfo.readAnnotation(c);
if(anno != null) {
addXsdExtensionInsideElement(anno, w);
}
}
}
public static <T, C> void addXsdAnnotationsOutsideElement(
ElementPropertyInfo<T, C> elementInfo, LocalElement el) {
/* INFO: For now, this can only affect <xsd:annotation>, i.e., class
* javax.xml.bind.annotation.Annotation. The other XSD elements are
* usually INSIDE the element they belong to... */
/* only write the annotation if location == OUTSIDE_ELEMENT ! */
javax.xml.bind.annotation.Annotation anno =
elementInfo.readAnnotation(javax.xml.bind.annotation.Annotation.class);
if(anno != null && anno.location() == AnnotationLocation.OUTSIDE_ELEMENT) {
addXsdExtension(anno, el);
}
}
public static <T, C> void addXsdAnnotationsOutsideElement(
PropertyInfo<T, C> elementInfo, Particle c) {
/* INFO: For now, this can only affect <xsd:annotation>, i.e., class
* javax.xml.bind.annotation.Annotation. The other XSD elements are
* usually INSIDE the element they belong to... */
/* only write the annotation if location == OUTSIDE_ELEMENT ! */
javax.xml.bind.annotation.Annotation anno =
elementInfo.readAnnotation(javax.xml.bind.annotation.Annotation.class);
if(anno != null && anno.location() == AnnotationLocation.OUTSIDE_ELEMENT) {
addXsdExtension(anno, c);
}
}
private static <T, C> void addXsdExtensionInsideElement(
Annotation anno, TypedXmlWriter obj) {
if(instanceOf(anno, javax.xml.bind.annotation.Annotation.class)) {
javax.xml.bind.annotation.Annotation annoCast = (javax.xml.bind.annotation.Annotation)anno;
/* only write the annotation if location == INSIDE_ELEMENT ! */
if(annoCast.location() == AnnotationLocation.INSIDE_ELEMENT) {
addXsdExtension(anno, obj);
}
} else if(instanceOf(anno, Assert.class)) {
addXsdExtension(anno, obj);
} else {
logger.warning("Unexpected annotation type: " + anno.getClass());
}
}
public static <T, C> void addXsdExtension(
Annotation annoInst, TypedXmlWriter obj) {
if(instanceOf(annoInst, javax.xml.bind.annotation.Annotation.class)) {
javax.xml.bind.annotation.Annotation anno =
(javax.xml.bind.annotation.Annotation)annoInst;
TypedXmlWriter annoEl = writeXsdAnnotationElement(obj,
anno.id(), anno.attributes());
for (AppInfo info : anno.appinfo()) {
TypedXmlWriter w = annoEl._element(new QName(NS_XSD, "appinfo"),
TypedXmlWriter.class);
if (info.source() != null && !info.source().equals("")) {
w._attribute(new QName("source"), info.source());
}
/* Use XML parser to allow XML content in appinfo */
writeXMLOrPCData(w, info.value());
}
for (Documentation doc : anno.documentation()) {
TypedXmlWriter w = annoEl._element(new QName(NS_XSD,
"documentation"), TypedXmlWriter.class);
if (doc.source() != null && !doc.source().equals("")) {
w._attribute(new QName("source"), doc.source());
}
if (doc.lang() != null && !doc.lang().equals("")) {
w._attribute(new QName(NS_XML, "lang"), doc.lang());
}
/* Use XML parser to allow XML content in documentation */
writeXMLOrPCData(w, doc.value());
}
} else if(instanceOf(annoInst, javax.xml.bind.annotation.Assert.class)) {
Assert anno = (Assert)annoInst;
if(checkXSD11Enabled()) {
writeXsdAssertElement(obj, anno.id(), anno.test(), anno.attributes());
if(anno.annotation() != null && anno.annotation().length > 0) {
/* recurse into this same method to write <xsd:annotation>s
* inside this <xsd:assert> */
for(javax.xml.bind.annotation.Annotation xsdAnno : anno.annotation()) {
addXsdExtension(xsdAnno, obj);
}
}
}
} else {
logger.warning("Unexpected annotation instance: " + annoInst);
}
}
/**
* Try parsing a value as an XML root element. Returns a corresponding XML Document
* if the string value is a valid XML root element, otherwise null.
* @param value
* @return
*/
private static Document parseValueAsXML(String value) {
try {
if(value == null || !value.trim().startsWith("<")) {
return null;
}
DocumentBuilder dBuilder = XML_FACTORY.newDocumentBuilder();
Document doc = dBuilder.parse(new ByteArrayInputStream(value.getBytes()));
doc.getDocumentElement().normalize();
logger.fine("Treating string as valid XML: '" + value + "'");
return doc;
} catch (Exception e) {
logger.fine("Cannot parse value as XML, treating as regular string: '" + value + "'");
return null;
}
}
/**
* If the passed value is a valid XML root element, then we parse it and
* write the XML element to the given TypedXmlWriter. Otherwise, the
* value will be written to TypedXmlWriter as a PCDATA string (i.e.,
* characters like '<', '&' etc. will be replaced by '<', '&' etc.).
* @param w
* @param value
*/
private static void writeXMLOrPCData(TypedXmlWriter w, String value) {
Document doc = parseValueAsXML(value);
if(doc == null) {
w._pcdata(value);
return;
}
try {
writeXML(w, value);
} catch (Exception e) {
logger.info("Unable to write XML data to TXW2 serializer: " + e);
w._pcdata(value);
}
}
private static void writeXML(final TypedXmlWriter w, String value) throws Exception {
TXWSerializer ser = (TXWSerializer)ResultFactory.createSerializer(new TXWResult(w));
new DOMtoTXW(w).convert(value);
}
public static <T, C> boolean hasXsdExtensions(ClassInfo<T, C> ci) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(ci, c)) {
return true;
}
}
return false;
}
public static <T, C> boolean hasXsdExtensions(TypeRef<T, C> t) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(t, c)) {
return true;
}
}
return false;
}
public static <T, C> boolean hasXsdExtensions(AttributePropertyInfo<T, C> info) {
for(Class<? extends Annotation> c : EXT_ANNO_CLASSES_AT_START) {
if(hasXsdExtension(info, c)) {
return true;
}
}
return false;
}
public static <T, C> boolean hasXsdExtension(ClassInfo<T, C> ci, Class<? extends Annotation> annoClass) {
Annotation anno = getXsdExtensionAnnotation(ci, annoClass);
return anno != null;
}
public static <T> boolean hasXsdExtension(T type, Class<? extends Annotation> annoClass) {
Annotation anno = getXsdExtensionAnnotation(type, annoClass);
return anno != null;
}
public static <T, C> boolean hasXsdExtension(TypeRef<T, C> t, Class<? extends Annotation> annoClass) {
Annotation anno = getXsdExtensionAnnotation(t, annoClass);
return anno != null;
}
public static <T, C> boolean hasXsdExtension(
AttributePropertyInfo<T, C> ap, Class<? extends Annotation> annoClass) {
Annotation anno = getXsdExtensionAnnotation(ap, annoClass);
return anno != null;
}
public static <T, C> boolean writeCustomOccurs(TypeRef<T, C> t,
LocalElement e, boolean isOptional, boolean repeated) {
MaxOccurs max = null;
MinOccurs min = null;
try {
max = (MaxOccurs) getAnnotationOfProperty(t.getSource(),
MaxOccurs.class);
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get @MaxOccurs annotation from type " + t, e2);
}
try {
min = (MinOccurs) getAnnotationOfProperty(t.getSource(),
MinOccurs.class);
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get @MinOccurs annotation from type " + t, e2);
}
if (min == null && max == null)
return false;
if (min != null) {
int value = (int) min.value();
e.minOccurs(value);
} else if (isOptional) {
e.minOccurs(0);
}
if (max != null) {
int value = (int) max.value();
e.maxOccurs(value);
} else if (repeated) {
e.maxOccurs("unbounded");
}
return true;
}
/* PRIVATE HELPER METHODS */
/**
* We need to disable XSD 1.1 features (e.g., <assert>)
* if running in wsimport context, otherwise we get
* parsing errors later on in the process:
* com.sun.tools.ws.wscompile.AbortException
at com.sun.tools.ws.processor.modeler.wsdl.JAXBModelBuilder.bind(JAXBModelBuilder.java:144)
at com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler.buildJAXBModel(WSDLModeler.java:2244)
at com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler.internalBuildModel(WSDLModeler.java:191)
at com.sun.tools.ws.processor.modeler.wsdl.WSDLModeler.buildModel(WSDLModeler.java:137)
* Disabling has to be done manually by setting XSD_11_ENABLED
*/
private static boolean checkXSD11Enabled() {
return XSD_11_ENABLED.get();
}
private static <T> Set<Package> extractPackage(T type) {
Set<Package> packages = new HashSet<Package>();
if(type instanceof Class<?>) {
Class<?> cl = (Class<?>) type;
Package pkg = cl.getPackage();
packages.add(pkg);
} else {
/* If jaxb-facets is used in the context of JAXB schemagen,
* the incoming parameter 'type' is not Class<?>, but
* com.sun.tools.javac.code.Type$ClassType. Since
* we don't want a hard-coded dependency on that class
* within jaxb-facets, we use a workaround here. */
try {
String className = type.toString();
String packageName = className.substring(0, className.lastIndexOf("."));
Package pkg = Package.getPackage(packageName);
if(pkg != null) {
/* TODO: pkg seems to be null here all the time.
* This means that package-level annotations are
* currently not supported for schemagen-based JAXB,
* because the schemagen mechanism is based on on-the-fly
* compilation and hence reflection (classes/packages)
* is not available at runtime. This shall be fixed
* in a future release. */
packages.add(pkg);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to derive package name from class type: " + type, e);
}
}
return packages;
}
private static boolean instanceOf(Annotation annoInst,
Class<? extends Annotation> clazz) {
if(annoInst == null) {
return false;
}
/* if we deal with a java.lang.reflect.Proxy instance,
* things get a bit nasty...
* FIXME find better approach, and check if needed at all!! */
if(Proxy.isProxyClass(annoInst.getClass())) {
AnnotationInvocationHandler h = (AnnotationInvocationHandler)
AnnotationUtils.PROXY_HANDLERS.get(annoInst);
if(h != null) {
return isAssignableFrom(clazz, h.annoClass);
}
}
return isAssignableFrom(clazz, annoInst.getClass());
}
private static boolean isAssignableFrom(Class<?> clazz1, Class<?> clazz2) {
/* Due to possible classloading magic taking place, we simply compare
* canonical classnames here (and do not compare classes directly) */
if(clazz1.getName().equals(clazz2.getName())) {
return true;
}
/* if we deal with some other class */
if(clazz1.isAssignableFrom(clazz2)) {
return true;
}
return false;
}
private static <T, C, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
ClassInfo<T, C> ci, Class<AnnoT> annoClass) {
return getXsdExtensionAnnotation(ci.getType(), annoClass);
}
private static <T, C, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
EnumConstant c, Class<AnnoT> annoClass) {
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
Documentation doc = AnnotationUtils
.getAnnoFromEnum((EnumConstant) c, Documentation.class);
return (AnnoT)getXsdAnnotationAnnotation(null, doc, null);
} else if(isAssignableFrom(Assert.class, annoClass)) {
return (AnnoT)AnnotationUtils.getAnnoFromEnum((EnumConstant) c, annoClass);
} else {
throw new IllegalArgumentException();
}
}
private static <T, C, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
Class<?> clazz, Class<AnnoT> annoClass) {
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
javax.xml.bind.annotation.Annotation anno = clazz
.getAnnotation(javax.xml.bind.annotation.Annotation.class);
AppInfo appinfo = clazz.getAnnotation(AppInfo.class);
Documentation doc = clazz.getAnnotation(Documentation.class);
return (AnnoT)getXsdAnnotationAnnotation(anno, doc, appinfo);
} else {
throw new IllegalArgumentException("" + annoClass);
}
}
private static <T, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
T type, Class<AnnoT> annoClass) {
AnnoT anno = null;
if (type instanceof Class<?>) {
Class<?> clazz = (Class<?>) type;
anno = (AnnoT)clazz.getAnnotation(annoClass);
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
AppInfo appinfo = clazz.getAnnotation(AppInfo.class);
Documentation doc = clazz.getAnnotation(Documentation.class);
return (AnnoT)getXsdAnnotationAnnotation(
(javax.xml.bind.annotation.Annotation)anno, doc, appinfo);
} else if(isAssignableFrom(Assert.class, annoClass)) {
return (AnnoT)clazz.getAnnotation(Assert.class);
} else {
throw new IllegalArgumentException("" + annoClass);
}
} else if (type instanceof Package) {
Package pkg = (Package) type;
anno = pkg.getAnnotation(annoClass);
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
AppInfo appinfo = pkg.getAnnotation(AppInfo.class);
Documentation doc = pkg.getAnnotation(Documentation.class);
return (AnnoT)getXsdAnnotationAnnotation(
(javax.xml.bind.annotation.Annotation)anno, doc, appinfo);
} else if(isAssignableFrom(Assert.class, annoClass)) {
return (AnnoT)pkg.getAnnotation(Assert.class);
} else {
throw new IllegalArgumentException("" + annoClass);
}
} else if (type instanceof EnumConstant) {
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
Documentation doc = AnnotationUtils
.getAnnoFromEnum((EnumConstant) type, Documentation.class);
return (AnnoT)XmlSchemaEnhancer
.getXsdAnnotationAnnotation(null, doc, null);
} else if(isAssignableFrom(Assert.class, annoClass)) {
return (AnnoT)AnnotationUtils
.getAnnoFromEnum((EnumConstant) type, Assert.class);
} else {
throw new IllegalArgumentException("" + annoClass);
}
} else if (type.getClass().getName().endsWith("ClassType")) {
anno = (AnnoT)SchemagenUtil.extractAnnotation(type, annoClass);
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
AppInfo appinfo = SchemagenUtil.extractAnnotation(type, AppInfo.class);
Documentation doc = SchemagenUtil.extractAnnotation(type, Documentation.class);
return (AnnoT)getXsdAnnotationAnnotation(
(javax.xml.bind.annotation.Annotation)anno, doc, appinfo);
} else if(isAssignableFrom(Assert.class, annoClass)) {
return (AnnoT)SchemagenUtil.extractAnnotation(type, Assert.class);
} else {
throw new IllegalArgumentException("" + annoClass);
}
} else {
logger.warning("Cannot get annotation '@" + annoClass + "' for unknown type '" + type + "'");
}
return null;
}
private static <T, C, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
TypeRef<T, C> t, Class<AnnoT> annoClass) {
return getXsdExtensionAnnotation(t.getSource(), annoClass);
}
private static <T, C, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
AttributePropertyInfo<T, C> t, Class<AnnoT> annoClass) {
return getXsdExtensionAnnotation(t.getSource(), annoClass);
}
private static <T, C, AnnoT extends Annotation> AnnoT getXsdExtensionAnnotation(
PropertyInfo<T, C> propInfo, Class<AnnoT> annoClass) {
if(isAssignableFrom(javax.xml.bind.annotation.Annotation.class, annoClass)) {
javax.xml.bind.annotation.Annotation anno = null;
AppInfo appinfo = null;
Documentation doc = null;
try {
Object value = getAnnotationOfProperty(propInfo,
javax.xml.bind.annotation.Annotation.class);
if (value instanceof javax.xml.bind.annotation.Annotation) {
anno = (javax.xml.bind.annotation.Annotation) value;
}
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get XSD Annotation annotation from type " + propInfo,
e2);
}
try {
Object value = getAnnotationOfProperty(propInfo, AppInfo.class);
if (value instanceof AppInfo) {
appinfo = (AppInfo) value;
}
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get XSD AppInfo annotation from type " + propInfo, e2);
}
try {
Object value = getAnnotationOfProperty(propInfo, Documentation.class);
if (value instanceof Documentation) {
doc = (Documentation) value;
}
} catch (Exception e2) {
logger.log(
Level.WARNING,
"Unable to get XSD Documentation annotation from type " + propInfo,
e2);
}
AnnoT result = (AnnoT)getXsdAnnotationAnnotation(anno, doc, appinfo);
return result;
} else if(isAssignableFrom(Assert.class, annoClass)) {
try {
return (AnnoT)getAnnotationOfProperty(propInfo, Assert.class);
} catch (Exception e) {
logger.log(
Level.WARNING,
"Unable to get @javax.xml.bind.annotation.Assert annotation from type " + propInfo,
e);
}
}
throw new IllegalArgumentException("" + annoClass);
}
private static ClassLoader selectClassLoader(Object ... objects) {
ClassLoader cl = null;
for(Object o : objects) {
if(o != null) {
cl = o.getClass().getClassLoader();
break;
}
}
// Java7 users have encountered problems here.
// Fallback to system classloader is necessary for compatibility
// with Java7 JAXB bootstrapping/overriding mechanism.
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
return cl;
}
protected static <T, C> Assert getXsdAssertAnnotation(String id, String test,
String xpathDefaultNamespace, Attribute[] attributes, Annotation[] annotation) {
final Map<String, Object> annoValues = new HashMap<String, Object>();
annoValues.put("id", id);
annoValues.put("test", test);
annoValues.put("xpathDefaultNamespace", xpathDefaultNamespace);
annoValues.put("attributes", attributes);
annoValues.put("annotation", annotation);
annoValues.put("xpathDefaultNamespace", xpathDefaultNamespace);
ClassLoader cl = selectClassLoader();
Assert anno = AnnotationUtils.createAnnotationProxy(Assert.class, annoValues, cl);
return anno;
}
protected static <T, C> javax.xml.bind.annotation.Annotation getXsdAnnotationAnnotation(
javax.xml.bind.annotation.Annotation _anno, Documentation _doc, AppInfo _appinfo) {
// jpell - no point if none of the params is provided.
if (_anno == null && _doc == null && _appinfo == null) {
return null;
}
ClassLoader cl = selectClassLoader(_anno, _doc,_appinfo);
final Map<String, Object> annoValues = new HashMap<String, Object>();
annoValues.put("id", "");
annoValues.put("appinfo", new AppInfo[] {});
annoValues.put("attributes", new Attribute[] {});
annoValues.put("documentation", new Documentation[] {});
annoValues.put("location", AnnotationLocation.INSIDE_ELEMENT);
boolean hasAnno = false;
try {
if (_anno instanceof javax.xml.bind.annotation.Annotation) {
annoValues.put("id", _anno.id());
annoValues.put("appinfo", _anno.appinfo());
annoValues.put("attributes", _anno.attributes());
annoValues.put("documentation", _anno.documentation());
annoValues.put("location", _anno.location());
hasAnno = true;
}
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get XSD Annotation annotation from type "
+ _anno, e2);
}
try {
if (_appinfo instanceof AppInfo) {
AppInfo[] appinfos = (AppInfo[]) annoValues.get("appinfo");
annoValues.put("appinfo", concat(appinfos, _appinfo));
hasAnno = true;
}
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get XSD AppInfo annotation from type "
+ _appinfo, e2);
}
try {
if (_doc instanceof Documentation) {
Documentation[] docs = (Documentation[]) annoValues
.get("documentation");
annoValues.put("documentation", concat(docs, _doc));
hasAnno = true;
}
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get XSD Documentation annotation from type "
+ _doc, e2);
}
javax.xml.bind.annotation.Annotation anno = AnnotationUtils.
createAnnotationProxy(javax.xml.bind.annotation.Annotation.class, annoValues, cl);
return hasAnno ? anno : null;
}
private static <T, C> Facets getFacetsAnnotation(TypeRef<T, C> t) {
if (!t.getTarget().isSimpleType())
return null;
try {
Object value = getAnnotationOfProperty(t.getSource(), Facets.class);
if (value instanceof Facets)
return (Facets) value;
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get Facets annotation from type " + t, e2);
}
return null;
}
private static <T, C> Facets getFacetsAnnotation(ValuePropertyInfo<T, C> vp) {
if (!vp.getTarget().isSimpleType())
return null;
try {
Object value = getAnnotationOfProperty(vp.getSource(), Facets.class);
if (value instanceof Facets)
return (Facets) value;
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get Facets annotation from type " + vp, e2);
}
return null;
}
private static <T, C> Facets getFacetsAnnotation(
AttributePropertyInfo<T, C> t) {
/* make sure this is either
* - a simple type like string, or
* - an IDREF, which is also considered a simple type
*/
if (!t.getTarget().isSimpleType() && t.getSource().id() != ID.IDREF)
return null;
try {
Object value = getAnnotationOfProperty(t.getSource(), Facets.class);
if (value instanceof Facets)
return (Facets) value;
} catch (Exception e2) {
logger.log(Level.WARNING,
"Unable to get Facets annotation from type " + t, e2);
}
return null;
}
private static <T, C> Object getAnnotationOfProperty(
PropertyInfo<T, C> info, Class<? extends Annotation> annoClass)
throws Exception {
if (annoClass == Facets.class) {
Object result = facetFilter.filterAnnotation(annoClass, info.readAnnotation(Facets.class), info);
if (result != null) {
return result;
}
} else if (annoClass == MaxOccurs.class && info.hasAnnotation(MaxOccurs.class)) {
return info.readAnnotation(MaxOccurs.class);
} else if (annoClass == MinOccurs.class) {
Object result = facetFilter.filterAnnotation(annoClass, info.readAnnotation(MinOccurs.class), info);
if (result != null) {
return result;
}
} else if (annoClass == Documentation.class && info.hasAnnotation(Documentation.class)) {
return info.readAnnotation(Documentation.class);
} else if (annoClass == AppInfo.class && info.hasAnnotation(AppInfo.class)) {
return info.readAnnotation(AppInfo.class);
} else if (info.parent() == null) {
return null;
} else if (!(info.parent().getType() instanceof Class<?>)) {
return null;
}
String name = info.getName();
Object type = info.parent().getType();
if(info.parent().getType() instanceof ClassType) {
/* We are (most likely) executing in the scope of a schemagen run. It seems
* that at this point it is sufficient to return null from this method.
* This is also covered by a test case named "SchemagenTest", and
* it seems to work (see also github issue #23). */
return null;
}
if(type instanceof Class<?>) {
Class<?> parent = (Class<?>) info.parent().getType();
return getAnnotationOfProperty(parent, name, annoClass);
} else {
throw new RuntimeException("Unexpected type of property parent: " + info.parent().getType());
}
}
protected static <T extends Annotation> T getAnnotationOfProperty(
Class<?> parent, String fieldName, Class<T> annoClass)
throws Exception {
try {
Field field = findAnnotatedField(parent, fieldName);
if (field == null)
return null;
Object a = facetFilter.filterAnnotation(annoClass, getAnnotation(field, annoClass), field);
return (T) a;
} catch (Exception e) {
throw new RuntimeException("Could not get annotation '"
+ annoClass.getSimpleName() + "' of field " + fieldName
+ " of class " + parent, e);
}
}
private static Field findAnnotatedField(Class<?> parent, String fieldName) {
Field field = null;
for (Field f : parent.getDeclaredFields()) {
if (f.getName().equals(fieldName)) {
field = f;
break;
} else {
if (getAnnotation(f, XmlElement.class) != null) {
XmlElement e = (XmlElement) getAnnotation(f,
XmlElement.class);
if (fieldName.equals(e.name())) {
field = f;
break;
}
}
if (getAnnotation(f, XmlAttribute.class) != null) {
XmlAttribute a = (XmlAttribute) getAnnotation(f,
XmlAttribute.class);
if (fieldName.equals(a.name())) {
field = f;
break;
}
}
}
}
return field;
}
protected static <T extends Annotation> T getAnnotation(AccessibleObject field,
Class<T> annoClass) {
for (Annotation anno : field.getAnnotations()) {
try {
return annoClass.cast(anno);
} catch (Exception e) {
/* swallow */
}
if (anno instanceof Proxy) {
try {
Object handler = Proxy.getInvocationHandler(anno);
if (handler instanceof InvocationHandler) {
T annoObj = convertToAnnotation(
(InvocationHandler) handler, annoClass);
return (T) annoObj;
}
} catch (Exception e) {
/* swallow */
}
}
if (annoClass.equals(anno.getClass())
|| annoClass.isAssignableFrom(anno.getClass())) {
return (T) anno;
}
}
return null;
}
private static <T extends Annotation> T convertToAnnotation(
final InvocationHandler handler, final Class<T> expectedClass) {
try {
Field f = InvocationHandler.class.getDeclaredField("memberValues");
f.setAccessible(true);
Map<String, Object> memberValues = (Map<String, Object>) f
.get(handler);
Field f1 = InvocationHandler.class.getDeclaredField("type");
f1.setAccessible(true);
final Class<?> type = (Class<?>) f1.get(handler);
if (!expectedClass.getName().equals(type.getName())) {
throw new RuntimeException("Not the expected annotation type: "
+ type + " != " + expectedClass);
}
T anno = (T) Proxy.newProxyInstance(expectedClass.getClassLoader(),
new Class[] { expectedClass }, new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) {
Object o = null;
try {
o = handler.invoke(proxy, method, args);
if (o != null) {
Class<?> componentClass = o.getClass();
if (componentClass.isArray()) {
componentClass = componentClass
.getComponentType();
}
if (!componentClass.isPrimitive()
&& !componentClass.getName()
.startsWith("java.lang")) {
ClassLoader cl = expectedClass
.getClassLoader() != null ? expectedClass
.getClassLoader() : ClassLoader
.getSystemClassLoader();
String name = componentClass.getName();
if (cl.loadClass(name) != componentClass) {
/*
* we need to import/convert the
* class into the classloader of
* expectedClass
*/
if (componentClass.getName()
.endsWith("WhiteSpace")) {
o = WhiteSpace.valueOf(o
.toString());
} else {
logger.warning("Unknown/Unexpected class "
+ componentClass);
}
}
}
}
} catch (Throwable e) {
logger.log(Level.WARNING, "", e);
}
return o;
}
});
return anno;
} catch (Exception e) {
throw new RuntimeException(
"Unable to convert AnnotationInvocationHandler to annotation.",
e);
}
}
private static <T, C> TypedXmlWriter getRestriction(
AttributePropertyInfo<T, C> info, TypedXmlWriter obj) {
return getRestriction(info, obj, null);
}
private static <T, C> TypedXmlWriter getRestriction(
AttributePropertyInfo<T, C> info, TypedXmlWriter obj,
TypedXmlWriter w) {
QName restrName = info.getTarget().getTypeName();
if(info.getSource().id() == ID.ID) {
restrName = new QName(NS_XSD, "ID");
} else if(info.getSource().id() == ID.IDREF) {
restrName = new QName(NS_XSD, "IDREF");
}
return getRestriction(restrName, obj, w);
}
private static <T, C> TypedXmlWriter getRestriction(
ValuePropertyInfo<T, C> info, TypedXmlWriter obj, TypedXmlWriter w) {
return getRestriction(info.getTarget().getTypeName(), obj, w);
}
private static <T, C> TypedXmlWriter getRestriction(TypeRef<T, C> t,
TypedXmlWriter obj, TypedXmlWriter w) {
if (w != null) {
return w;
}
QName schemaType = t.getSource() == null ? null : t.getSource()
.getSchemaType();
if (schemaType == null)
schemaType = t.getTarget().getTypeName();
return getRestriction(schemaType, obj, w);
}
private static <T, C> TypedXmlWriter getRestriction(
QName typeName, TypedXmlWriter obj, TypedXmlWriter w) {
if (w != null) {
return w;
}
TypedXmlWriter st = obj._element(new QName(NS_XSD, "simpleType"),
TypedXmlWriter.class);
TypedXmlWriter r = st._element(new QName(NS_XSD, "restriction"),
TypedXmlWriter.class);
r._attribute("base", typeName);
return r;
}
private static <T, C> TypedXmlWriter writeXsdAnnotationElement(TypedXmlWriter obj,
String annoID, Attribute[] otherAttributes) {
TypedXmlWriter anno = obj._element(new QName(NS_XSD, "annotation"),
TypedXmlWriter.class);
if (annoID != null && !annoID.trim().isEmpty()) {
anno._attribute(new QName("id"), annoID);
}
if (otherAttributes != null && otherAttributes.length > 0) {
for(Attribute attr : otherAttributes) {
// namespace is compulsory
QName attrName = new QName(attr.namespace(), attr.name());
anno._attribute(attrName, attr.value());
}
}
return anno;
}
private static <T, C> TypedXmlWriter writeXsdAssertElement(TypedXmlWriter obj,
String id, String test, Attribute[] otherAttributes) {
TypedXmlWriter ass = obj._element(new QName(NS_XSD, "assert"),
TypedXmlWriter.class);
if (id != null && !id.trim().isEmpty()) {
ass._attribute(new QName("id"), id);
}
if (test != null && !test.trim().isEmpty()) {
ass._attribute(new QName("test"), test);
}
if (otherAttributes != null && otherAttributes.length > 0) {
for(Attribute attr : otherAttributes) {
// namespace is compulsory
QName attrName = new QName(attr.namespace(), attr.name());
ass._attribute(attrName, attr.value());
}
}
return ass;
}
/**
* Note: we are returning a SortedMap here in order to make the schema
* generation process deterministic. Yossi Cohen (YossiCO@Amdocs.com)
* reported indeterministic behavior (different order of generated XML
* nodes) in the old version where we still used a regular HashMap,
* which does not preserve the order of items...
*
* @param facetsAnnotation
* @return
* @throws Exception
*/
protected static SortedMap<String, List<String>> getDefinedFacets(
Facets facetsAnnotation) throws Exception {
List<Method> annoMethods = new LinkedList<Method>();
SortedMap<String, List<String>> result = new TreeMap<String, List<String>>();
if (facetsAnnotation == null)
return result;
for (Method m : Facets.class.getDeclaredMethods()) {
if (m.isAnnotationPresent(FacetDefinition.class))
annoMethods.add(m);
}
for (Method m : annoMethods) {
/* additional code suggested by Jason Pell (jason@pellcorp.com) */
FacetDefinition facetDefinition = m
.getAnnotation(FacetDefinition.class);
String facetName = m.getName();
if (facetDefinition.xsdAttributeName() != null
&& facetDefinition.xsdAttributeName().length() > 0) {
facetName = facetDefinition.xsdAttributeName();
}
/* end additional code */
Object value = null;
try {
value = m.invoke(facetsAnnotation);
} catch (Exception e) {
// sometimes happens due to our proxying mechanism, especially for javac/schemagen.
}
Object defaultValue = m.getDefaultValue();
if (value != null && !value.equals(defaultValue)) {
if (!result.containsKey(facetName)) {
result.put(facetName, new LinkedList<String>());
}
if (value instanceof String[]) {
for (String s : (String[]) value)
result.get(facetName).add(s);
} else {
result.get(facetName).add("" + value);
}
}
}
return result;
}
/**
* Helper method to concatenate two arrays.
*
* @param first
* @param second
* @return
*/
public static <T> T[] concat(T[] first, T[] second) {
T[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
/**
* Helper method to concatenate an arrays with an additional value.
*
* @param first
* @param second
* @return
*/
public static <T> T[] concat(T[] first, T second) {
T[] result = Arrays.copyOf(first, first.length + 1);
System.arraycopy(first, 0, result, 0, first.length);
result[result.length - 1] = second;
return result;
}
/* COMPATIBILITY METHODS TO DEAL WITH com.sun.xml.internal.bind.* */
// /** for compatibility with Java 1.7 */
// public static <T, C> boolean hasExtendedAnnotations(
// com.sun.xml.internal.bind.v2.model.core.AttributePropertyInfo<T, C> info) {
// return hasFacets(info) || hasXsdAnnotations(info);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> boolean hasExtendedAnnotations(
// com.sun.xml.internal.bind.v2.model.core.TypeRef<T, C> t) {
// return hasFacets(t) || hasXsdAnnotations(t);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addFacets(
// com.sun.xml.internal.bind.v2.model.core.ValuePropertyInfo<T, C> vp,
// com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleRestriction sr) {
// XmlSchemaEnhancerJava7.addFacets(vp, sr);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addFacets(
// com.sun.xml.internal.bind.v2.model.core.TypeRef<T, C> t,
// com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement e) {
// XmlSchemaEnhancerJava7.addFacets(t, e);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addFacets(
// com.sun.xml.internal.bind.v2.model.core.AttributePropertyInfo<T, C> info,
// com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalAttribute attr) {
// XmlSchemaEnhancerJava7.addFacets(info, attr);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> boolean hasFacets(
// com.sun.xml.internal.bind.v2.model.core.TypeRef<T, C> t) {
// return XmlSchemaEnhancerJava7.hasFacets(t);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> boolean hasFacets(
// com.sun.xml.internal.bind.v2.model.core.AttributePropertyInfo<T, C> ap) {
// return XmlSchemaEnhancerJava7.hasFacets(ap);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addXsdAnnotations(T type,
// com.sun.xml.internal.txw2.TypedXmlWriter w) {
// XmlSchemaEnhancerJava7.addXsdAnnotations(type, w);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addXsdAnnotations(
// Set<com.sun.xml.internal.bind.v2.model.core.ClassInfo<T, C>> classes,
// Set<com.sun.xml.internal.bind.v2.model.core.EnumLeafInfo<T, C>> enums,
// Set<com.sun.xml.internal.bind.v2.model.core.ArrayInfo<T, C>> arrays,
// com.sun.xml.internal.txw2.TypedXmlWriter w) {
// Set<Package> annotatedPackages = new HashSet<Package>();
// for (com.sun.xml.internal.bind.v2.model.core.ClassInfo<T, C> c : classes) {
// Class<?> cl = (Class<?>) c.getType();
// Package pkg = cl.getPackage();
// annotatedPackages.add(pkg);
// }
// for (com.sun.xml.internal.bind.v2.model.core.EnumLeafInfo<T, C> c : enums) {
// Class<?> cl = (Class<?>) c.getType();
// Package pkg = cl.getPackage();
// annotatedPackages.add(pkg);
// }
// for (com.sun.xml.internal.bind.v2.model.core.ArrayInfo<T, C> c : arrays) {
// Class<?> cl = (Class<?>) c.getType();
// Package pkg = cl.getPackage();
// annotatedPackages.add(pkg);
// }
// for (Package p : annotatedPackages) {
// XmlSchemaEnhancerJava7.addXsdAnnotations(p, w);
// }
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addXsdAnnotations(
// com.sun.xml.internal.bind.v2.model.core.ClassInfo<T, C> ci,
// com.sun.xml.internal.txw2.TypedXmlWriter w) {
// XmlSchemaEnhancerJava7.addXsdAnnotations(ci, w);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addXsdAnnotations(
// com.sun.xml.internal.bind.v2.model.core.AttributePropertyInfo<T, C> _info,
// com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalAttribute _attr) {
// XmlSchemaEnhancerJava7.addXsdAnnotations(_info, _attr);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addXsdAnnotations(
// com.sun.xml.internal.bind.v2.model.core.TypeRef<T, C> _info,
// com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement _el) {
// XmlSchemaEnhancerJava7.addXsdAnnotations(_info, _el);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> void addXsdAnnotations(
// javax.xml.bind.annotation.Annotation anno,
// com.sun.xml.internal.txw2.TypedXmlWriter obj) {
// XmlSchemaEnhancerJava7.addXsdAnnotations(anno, obj);
// }
// /** for compatibility with Java 1.7 */
// public static <T, C> boolean writeCustomOccurs(
// com.sun.xml.internal.bind.v2.model.core.TypeRef<T, C> t,
// com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement e,
// boolean isOptional, boolean repeated) {
// return XmlSchemaEnhancerJava7.writeCustomOccurs(t, e, isOptional,
// repeated);
// }
}