void () { PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage(""); assertNotNull(rootPackage); VirtualFile annotationsRoot = getAnnotationsRoot(); JavaRecursiveElementVisitor visitor = new PackageVisitor(GlobalSearchScope.moduleWithLibrariesScope(getModule())) { @Override protected void visitSubPackage(PsiPackage aPackage, PsiClass[] classes) { LOG.debug(aPackage.getQualifiedName()); Map<String, Map<String, PsiNameValuePair[]>> annotations = new TreeMap<>(); for (PsiClass aClass : classes) processClass(aClass, annotations); saveXmlForPackage(aPackage.getQualifiedName(), annotations, annotationsRoot); } private void processClass(PsiClass aClass, Map<String, Map<String, PsiNameValuePair[]>> annotations) { for (PsiMethod method : aClass.getMethods()) annotateMethod(method, annotations); for (PsiField field : aClass.getFields()) annotateField(field, annotations); for (PsiClass innerClass : aClass.getInnerClasses()) processClass(innerClass, annotations); } private void annotateMethod(PsiMethod method, Map<String, Map<String, PsiNameValuePair[]>> annotations) { String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE); if (INFERRED_TEST_METHOD.equals(methodKey)) return; if (!EXTERNAL_TEST_METHOD.equals(methodKey)) { PsiAnnotation inferredContractAnnotation = findInferredAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT); if (inferredContractAnnotation != null) { PsiNameValuePair[] attributes = inferredContractAnnotation.getParameterList().getAttributes(); annotate(annotations, method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT, attributes); } } PsiAnnotation inferredNotNullMethodAnnotation = findInferredAnnotation(method, AnnotationUtil.NOT_NULL); if (inferredNotNullMethodAnnotation != null) { annotate(annotations, method, AnnotationUtil.NOT_NULL, PsiNameValuePair.EMPTY_ARRAY); } PsiAnnotation inferredNullableMethodAnnotation = findInferredAnnotation(method, AnnotationUtil.NULLABLE); if (inferredNullableMethodAnnotation != null) { annotate(annotations, method, AnnotationUtil.NULLABLE, PsiNameValuePair.EMPTY_ARRAY); } for (PsiParameter parameter : method.getParameterList().getParameters()) { PsiAnnotation inferredNotNull = findInferredAnnotation(parameter, AnnotationUtil.NOT_NULL); if (inferredNotNull != null) { annotate(annotations, parameter, AnnotationUtil.NOT_NULL, PsiNameValuePair.EMPTY_ARRAY); } PsiAnnotation inferredNullable = findInferredAnnotation(parameter, AnnotationUtil.NULLABLE); if (inferredNullable != null) { annotate(annotations, parameter, AnnotationUtil.NULLABLE, PsiNameValuePair.EMPTY_ARRAY); } } } private void annotateField(PsiField field, Map<String, Map<String, PsiNameValuePair[]>> annotations) { PsiAnnotation inferredNotNullMethodAnnotation = findInferredAnnotation(field, AnnotationUtil.NOT_NULL); if (inferredNotNullMethodAnnotation != null) { annotate(annotations, field, AnnotationUtil.NOT_NULL, PsiNameValuePair.EMPTY_ARRAY); } } private void annotate(Map<String, Map<String, PsiNameValuePair[]>> annotations, PsiModifierListOwner owner, String annotationFQN, PsiNameValuePair[] attributes) { String key = PsiFormatUtil.getExternalName(owner, false, Integer.MAX_VALUE); annotations.computeIfAbsent(key, k -> new TreeMap<>()).put(annotationFQN, attributes); } private void saveXmlForPackage(String packageName, Map<String, Map<String, PsiNameValuePair[]>> annotations, VirtualFile root) { if (annotations.isEmpty()) return; String xmlContent = EntryStream.of(annotations) .mapValues(map -> EntryStream.of(map).mapKeyValue(ModCommandAwareExternalAnnotationsManager::createAnnotationTag).joining()) .mapKeyValue((externalName, content) -> "<item name='" + StringUtil.escapeXmlEntities(externalName) + "'>\n" + content.trim() + "\n</item>\n") .joining("", "<root>\n", "</root>"); WriteCommandAction.runWriteCommandAction(getProject(), () -> { XmlFile xml = ExternalAnnotationsManagerImpl.createAnnotationsXml(root, packageName, getPsiManager()); if (xml == null) throw new IllegalStateException("Unable to get XML for package " + packageName + "; root = " + root); xml.getVirtualFile().refresh(false, false); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject()); Document document = documentManager.getDocument(xml); document.setText(xmlContent); documentManager.commitDocument(document); CodeStyleManager.getInstance(getProject()).reformat(xml); FileDocumentManager.getInstance().saveDocument(document); }); } }; rootPackage.accept(visitor); }