void (@Nullable XmlFile annotationsFile, @NotNull List<ExternalAnnotation> annotations) { XmlTag rootTag = extractRootTag(annotationsFile); Map<String, List<ExternalAnnotation>> ownerToAnnotations = StreamEx.of(annotations) .mapToEntry(annotation -> { String externalName = getExternalName(annotation.getOwner()); return externalName == null ? null : StringUtil.escapeXmlEntities(externalName); }, Function.identity()) .distinct() .grouping(() -> new TreeMap<>(Comparator.nullsFirst(Comparator.naturalOrder()))); if (rootTag == null) { ownerToAnnotations.values().stream().flatMap(List::stream).forEach(annotation -> notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false)); return; } List<ExternalAnnotation> savedAnnotations = new ArrayList<>(); XmlTag startTag = null; for (Map.Entry<String, List<ExternalAnnotation>> entry : ownerToAnnotations.entrySet()) { @NonNls String ownerName = entry.getKey(); List<ExternalAnnotation> annotationList = entry.getValue(); for (ExternalAnnotation annotation : annotationList) { if (ownerName == null) { notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false); continue; } try { startTag = addAnnotation(rootTag, ownerName, annotation, startTag); savedAnnotations.add(annotation); } catch (IncorrectOperationException e) { LOG.error(e); notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false); } finally { dropAnnotationsCache(); markForUndo(annotation.getOwner().getContainingFile()); } } } commitChanges(annotationsFile); savedAnnotations.forEach(annotation -> notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), true)); }