/** * Convenience method for building a Map of package to classes. * * @return */ private Map<String, ArrayList<JavaClass>> buildPackageToJavaClassMap() { Map<String, ArrayList<JavaClass>> theMap = new HashMap<String, ArrayList<JavaClass>>(); Map<String, ArrayList<JavaClass>> xmlBindingsMap = new HashMap<String, ArrayList<JavaClass>>(); XmlBindings xmlBindings; for (String packageName : xmlBindingMap.keySet()) { xmlBindings = xmlBindingMap.get(packageName); ArrayList classes = new ArrayList<JavaClass>(); // add binding classes - the Java Model will be used to get a // JavaClass via class name JavaTypes jTypes = xmlBindings.getJavaTypes(); if (jTypes != null) { for (JavaType javaType : jTypes.getJavaType()) { classes.add(jModelInput.getJavaModel().getClass(javaType.getName())); } } // add any enum types to the class list XmlEnums xmlEnums = xmlBindings.getXmlEnums(); if (xmlEnums != null) { for (XmlEnum xmlEnum : xmlEnums.getXmlEnum()) { classes.add(jModelInput.getJavaModel().getClass(xmlEnum.getJavaEnum())); } } theMap.put(packageName, classes); xmlBindingsMap.put(packageName, new ArrayList(classes)); } // add any other classes that aren't declared via external metadata for (JavaClass jClass : jModelInput.getJavaClasses()) { // need to verify that the class isn't already in the bindings file list String pkg = jClass.getPackageName(); ArrayList<JavaClass> existingXmlBindingsClasses = xmlBindingsMap.get(pkg); ArrayList<JavaClass> allExistingClasses = theMap.get(pkg); if (existingXmlBindingsClasses != null) { if (!classExistsInArray(jClass, existingXmlBindingsClasses)) { allExistingClasses.add(jClass); } } else { if (allExistingClasses != null) { allExistingClasses.add(jClass); } else { ArrayList classes = new ArrayList<JavaClass>(); classes.add(jClass); theMap.put(pkg, classes); } } } return theMap; }
/** * Process XmlBindings on a per package basis for a given AnnotationsPorcessor instance. * * @param annotationsProcessor */ public void processXML( AnnotationsProcessor annotationsProcessor, JavaModelInput jModelInput, TypeMappingInfo[] typeMappingInfos, JavaClass[] originalJavaClasses) { this.jModelInput = jModelInput; this.aProcessor = annotationsProcessor; Map<String, XmlEnum> xmlEnumMap = new HashMap<String, XmlEnum>(); annotationsProcessor.init(originalJavaClasses, typeMappingInfos); // build a map of packages to JavaClass so we only process the // JavaClasses for a given package additional classes - i.e. ones from // packages not listed in XML - will be processed later Map<String, ArrayList<JavaClass>> pkgToClassMap = buildPackageToJavaClassMap(); // process each XmlBindings in the map XmlBindings xmlBindings; for (String packageName : xmlBindingMap.keySet()) { ArrayList classesToProcess = pkgToClassMap.get(packageName); if (classesToProcess == null) { getLogger() .logWarning("jaxb_metadata_warning_no_classes_to_process", new Object[] {packageName}); continue; } xmlBindings = xmlBindingMap.get(packageName); // handle @XmlSchema override NamespaceInfo nsInfo = processXmlSchema(xmlBindings, packageName); if (nsInfo != null) { annotationsProcessor.addPackageToNamespaceMapping(packageName, nsInfo); } // build an array of JavaModel classes to process JavaClass[] javaClasses = (JavaClass[]) classesToProcess.toArray(new JavaClass[classesToProcess.size()]); // handle xml-enums // build a map of enum class names to XmlEnum objects XmlEnums xmlEnums = xmlBindings.getXmlEnums(); if (xmlEnums != null) { for (XmlEnum xmlEnum : xmlEnums.getXmlEnum()) { xmlEnumMap.put(xmlEnum.getJavaEnum(), xmlEnum); } } // pre-build the TypeInfo objects Map<String, TypeInfo> typeInfoMap = annotationsProcessor.preBuildTypeInfo(javaClasses); // handle package-level xml-schema-types List<XmlSchemaType> xmlSchemaTypes = null; XmlSchemaTypes sTypes = xmlBindings.getXmlSchemaTypes(); if (sTypes != null) { xmlSchemaTypes = sTypes.getXmlSchemaType(); } else { xmlSchemaTypes = new ArrayList<XmlSchemaType>(); } // handle package-level xml-schema-type if (xmlBindings.getXmlSchemaType() != null) { xmlSchemaTypes.add(xmlBindings.getXmlSchemaType()); } // process each xml-schema-type entry for (XmlSchemaType sType : xmlSchemaTypes) { JavaClass jClass = aProcessor.getHelper().getJavaClass(sType.getType()); if (jClass != null) { aProcessor.processSchemaType( sType.getName(), sType.getNamespace(), jClass.getQualifiedName()); } } nsInfo = annotationsProcessor.getPackageToNamespaceMappings().get(packageName); JavaTypes jTypes = xmlBindings.getJavaTypes(); if (jTypes != null) { for (JavaType javaType : jTypes.getJavaType()) { TypeInfo info = typeInfoMap.get(javaType.getName()); // package/class override order: // 1 - xml class-level // 2 - java object class-level // 3 - xml package-level // 4 - package-info.java // handle class-level @XmlJavaTypeAdapter override if (javaType.getXmlJavaTypeAdapter() != null) { info.setXmlJavaTypeAdapter(javaType.getXmlJavaTypeAdapter()); } // handle class-level @XmlAccessorOrder override if (javaType.isSetXmlAccessorOrder()) { info.setXmlAccessOrder(javaType.getXmlAccessorOrder()); } else if (!info.isSetXmlAccessOrder()) { // handle package-level @XmlAccessorOrder override if (xmlBindings.isSetXmlAccessorOrder()) { info.setXmlAccessOrder(xmlBindings.getXmlAccessorOrder()); } else { // finally, check the NamespaceInfo info.setXmlAccessOrder(nsInfo.getAccessOrder()); } } // handle class-level @XmlAccessorType override if (javaType.isSetXmlAccessorType()) { info.setXmlAccessType(javaType.getXmlAccessorType()); } else if (!info.isSetXmlAccessType()) { if (xmlBindings.isSetXmlAccessorType()) { // handle package-level @XmlAccessorType override info.setXmlAccessType(xmlBindings.getXmlAccessorType()); } else { // finally, check the NamespaceInfo info.setXmlAccessType(nsInfo.getAccessType()); } } // handle @XmlInlineBinaryData override if (javaType.isSetXmlInlineBinaryData()) { info.setInlineBinaryData(javaType.isXmlInlineBinaryData()); } // handle @XmlTransient override if (javaType.isSetXmlTransient()) { info.setXmlTransient(javaType.isXmlTransient()); } // handle @XmlRootElement if (javaType.getXmlRootElement() != null) { info.setXmlRootElement(javaType.getXmlRootElement()); } // handle @XmlSeeAlso override if (javaType.getXmlSeeAlso() != null && javaType.getXmlSeeAlso().size() > 0) { info.setXmlSeeAlso(javaType.getXmlSeeAlso()); } // handle @XmlType override if (javaType.getXmlType() != null) { info.setXmlType(javaType.getXmlType()); } // handle @XmlCustomizer override if (javaType.getXmlCustomizer() != null) { info.setXmlCustomizer(javaType.getXmlCustomizer()); } } } // apply package-level @XmlJavaTypeAdapters if (xmlBindings.getXmlJavaTypeAdapters() != null) { Map<String, TypeInfo> typeInfos = aProcessor.getTypeInfosForPackage(packageName); for (TypeInfo tInfo : typeInfos.values()) { List<XmlJavaTypeAdapter> adapters = xmlBindings.getXmlJavaTypeAdapters().getXmlJavaTypeAdapter(); for (XmlJavaTypeAdapter xja : adapters) { JavaClass adapterClass = jModelInput.getJavaModel().getClass(xja.getValue()); JavaClass boundType = jModelInput.getJavaModel().getClass(xja.getType()); if (boundType != null) { tInfo.addPackageLevelAdapterClass(adapterClass, boundType); } } } } // post-build the TypeInfo objects javaClasses = annotationsProcessor.postBuildTypeInfo(javaClasses); // now trigger the annotations processor to process the classes annotationsProcessor.processJavaClasses(javaClasses); // get the generated TypeInfo Map<String, TypeInfo> typeInfosForPackage = annotationsProcessor.getTypeInfosForPackage(packageName); // update xml-enum info if necessary for (String key : typeInfosForPackage.keySet()) { TypeInfo tInfo = typeInfosForPackage.get(key); if (tInfo.isEnumerationType()) { EnumTypeInfo etInfo = (EnumTypeInfo) tInfo; XmlEnum xmlEnum = xmlEnumMap.get(etInfo.getClassName()); if (xmlEnum != null) { JavaClass restrictionClass = aProcessor.getHelper().getJavaClass(xmlEnum.getValue()); // default to String if necessary if (restrictionClass == null) { restrictionClass = jModelInput.getJavaModel().getClass(String.class); } etInfo.setRestrictionBase(aProcessor.getSchemaTypeFor(restrictionClass)); for (XmlEnumValue xmlEnumValue : xmlEnum.getXmlEnumValue()) { // overwrite any existing entries (from annotations) etInfo.addJavaFieldToXmlEnumValuePair( true, xmlEnumValue.getJavaEnumValue(), xmlEnumValue.getValue()); } } } } // update TypeInfo objects based on the JavaTypes jTypes = xmlBindings.getJavaTypes(); if (jTypes != null) { for (JavaType javaType : jTypes.getJavaType()) { processJavaType(javaType, typeInfosForPackage.get(javaType.getName()), nsInfo); } } // remove the entry for this package from the map pkgToClassMap.remove(packageName); } // now process remaining classes Iterator<ArrayList<JavaClass>> classIt = pkgToClassMap.values().iterator(); while (classIt.hasNext()) { ArrayList<JavaClass> jClassList = classIt.next(); JavaClass[] jClassArray = (JavaClass[]) jClassList.toArray(new JavaClass[jClassList.size()]); annotationsProcessor.buildNewTypeInfo(jClassArray); annotationsProcessor.processJavaClasses(jClassArray); } // need to ensure that any bound types (from XmlJavaTypeAdapter) have // TypeInfo objects built for them - SchemaGenerator will require a // descriptor for each Map<String, TypeInfo> typeInfos = (Map<String, TypeInfo>) aProcessor.getTypeInfo().clone(); for (String key : typeInfos.keySet()) { JavaClass[] jClassArray; TypeInfo tInfo = typeInfos.get(key); for (Property prop : tInfo.getPropertyList()) { if (prop.isSetXmlJavaTypeAdapter()) { jClassArray = new JavaClass[] {prop.getActualType()}; aProcessor.buildNewTypeInfo(jClassArray); } } } aProcessor.finalizeProperties(); aProcessor.createElementsForTypeMappingInfo(); }