diff --git a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java index 62131cafd5..c4317eccc7 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java @@ -223,13 +223,22 @@ public class XWPFNumbering extends POIXMLDocumentPart { ctNumbering.addNewAbstractNum().set(abstractNum.getAbstractNum()); } else { abstractNum.setCtAbstractNum(ctNumbering.addNewAbstractNum()); - abstractNum.getAbstractNum().setAbstractNumId(BigInteger.valueOf(pos)); + BigInteger id = findNextAbstractNumberingId(); + abstractNum.getAbstractNum().setAbstractNumId(id); ctNumbering.setAbstractNumArray(pos, abstractNum.getAbstractNum()); } abstractNums.add(abstractNum); return abstractNum.getCTAbstractNum().getAbstractNumId(); } + private BigInteger findNextAbstractNumberingId() { + long maxId = 0; + for (XWPFAbstractNum num : abstractNums) { + maxId = Math.max(maxId, num.getAbstractNum().getAbstractNumId().longValue()); + } + return BigInteger.valueOf(maxId + 1); + } + /** * remove an existing abstractNum * diff --git a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java index dd241c14d3..9b312603bd 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFBugs.java @@ -196,6 +196,9 @@ class TestXWPFBugs { //attempt to remove item with numId 2 assertTrue(numbering.removeAbstractNum(BigInteger.valueOf(2))); + //adding one level to numbering with id 1 + numbering.getAbstractNum(BigInteger.valueOf(1)).getCTAbstractNum().addNewLvl(); + XWPFDocument docReloaded = writeOutAndReadBack(doc); XWPFNumbering numberingReloaded = docReloaded.getNumbering(); @@ -208,6 +211,14 @@ class TestXWPFBugs { } else { assertNotNull(abstractNum, "Failed for " + id); assertEquals(id, abstractNum.getAbstractNum().getAbstractNumId().longValue()); + + // we added one level for numbering with id "1" + if (id == 1) { + //TODO remaining issue from https://bz.apache.org/bugzilla/show_bug.cgi?id=66079 + //assertEquals(1, abstractNum.getAbstractNum().getLvlList().size()); + } else { + assertEquals(0, abstractNum.getAbstractNum().getLvlList().size()); + } } } diff --git a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java index c1806c946a..09d31dbf13 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java @@ -153,4 +153,16 @@ class TestXWPFNumbering { assertEquals("upperLetter", ctNumLvl.getLvl().getNumFmt().getVal().toString()); } } + + @Test + void testAddAbstractNum() throws IOException { + try (XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("NumberingWithOutOfOrderId.docx")) { + doc.getNumbering().addAbstractNum(new XWPFAbstractNum()); + long count = doc.getNumbering() + .getAbstractNums().stream() + .map(e -> e.getCTAbstractNum().getAbstractNumId().intValue()) + .distinct().count(); + assertEquals(doc.getNumbering().getAbstractNums().size(), count); + } + } } diff --git a/test-data/document/NumberingWithOutOfOrderId.docx b/test-data/document/NumberingWithOutOfOrderId.docx new file mode 100644 index 0000000000..6c471c43bd Binary files /dev/null and b/test-data/document/NumberingWithOutOfOrderId.docx differ