This is an automated email from the ASF dual-hosted git repository.

fanningpj pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 6d8f1901dc Allow null values in XWPFParagraph.get/setAlignment(). 
(#829)
6d8f1901dc is described below

commit 6d8f1901dcf6cd5f6261e93c293b4383858e1b1d
Author: Jacobo Aragunde PĂ©rez <[email protected]>
AuthorDate: Wed Jul 9 21:00:14 2025 +0200

    Allow null values in XWPFParagraph.get/setAlignment(). (#829)
    
    * Allow null values in XWPFParagraph.get/setAlignment().
    
    A null value in this field would indicate that the paragraph should
    follow the alignment provided by the style hierarchy.
    
    Fixes: https://bz.apache.org/bugzilla/show_bug.cgi?id=69720
    
    * Revert getAlignment() and implement isAlignmentSet() instead.
    
    * Replace test case file.
    
    * Implement XWPFParagraph.getTCPPr(create).
    
    It lets the caller choose if a new PPr should be created in case it
    doesn't exist.
    
    * use getCTPPr(boolean)
    
    * compile issue
    
    ---------
    
    Co-authored-by: PJ Fanning <[email protected]>
---
 .../apache/poi/xwpf/usermodel/XWPFParagraph.java   |  77 ++++++++++++++++-----
 .../java/org/apache/poi/xwpf/TestXWPFBugs.java     |  23 +++---
 .../poi/xwpf/usermodel/TestXWPFParagraph.java      |   7 ++
 test-data/document/bug-paragraph-alignment.docx    | Bin 0 -> 11916 bytes
 4 files changed, 83 insertions(+), 24 deletions(-)

diff --git 
a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java 
b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java
index 7f3ab37ff6..44bc523096 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java
@@ -482,16 +482,19 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * Returns the paragraph alignment which shall be applied to text in this
      * paragraph.
      * <p>
-     * If this element is not set on a given paragraph, its value is determined
+     * If this element is not set on a given paragraph, this function returns
+     * ParagraphAlignment.LEFT as a placeholder value, and isAlignmentSet()
+     * returns false. In such case, the alignment value must be determined
      * by the setting previously set at any level of the style hierarchy (i.e.
      * that previous setting remains unchanged). If this setting is never
      * specified in the style hierarchy, then no alignment is applied to the
      * paragraph.
      *
+     * @see #isAlignmentSet()
      * @return the paragraph alignment of this paragraph.
      */
     public ParagraphAlignment getAlignment() {
-        CTPPr pr = getCTPPr();
+        CTPPr pr = getCTPPr(false);
         return pr == null || !pr.isSetJc() ? ParagraphAlignment.LEFT
                 : ParagraphAlignment.valueOf(pr.getJc().getVal().intValue());
     }
@@ -506,13 +509,32 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * specified in the style hierarchy, then no alignment is applied to the
      * paragraph.
      *
-     * @param align the paragraph alignment to apply to this paragraph.
+     * @param align the paragraph alignment to apply to this paragraph. It can
+     *              be null to unset it and fall back to the style hierarchy.
      */
     public void setAlignment(ParagraphAlignment align) {
-        CTPPr pr = getCTPPr();
-        CTJc jc = pr.isSetJc() ? pr.getJc() : pr.addNewJc();
-        STJc.Enum en = STJc.Enum.forInt(align.getValue());
-        jc.setVal(en);
+        if (align == null) {
+            CTPPr pr = getCTPPr(false);
+            if (pr != null)
+                pr.unsetJc();
+        } else {
+            CTPPr pr = getCTPPr(true);
+            CTJc jc = pr.isSetJc() ? pr.getJc() : pr.addNewJc();
+            STJc.Enum en = STJc.Enum.forInt(align.getValue());
+            jc.setVal(en);
+        }
+    }
+
+    /**
+     * Returns true if the paragraph has a paragraph alignment value of its own
+     * or false in case it should fall back to the alignment value set by the
+     * paragraph style.
+     *
+     * @return boolean
+     */
+    public boolean isAlignmentSet() {
+        CTPPr pr = getCTPPr(false);
+        return pr != null && pr.isSetJc();
     }
 
     /**
@@ -548,7 +570,7 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * @return the vertical alignment of this paragraph.
      */
     public TextAlignment getVerticalAlignment() {
-        CTPPr pr = getCTPPr();
+        CTPPr pr = getCTPPr(false);
         return (pr == null || !pr.isSetTextAlignment()) ? TextAlignment.AUTO
                 : TextAlignment.valueOf(pr.getTextAlignment().getVal()
                 .intValue());
@@ -864,7 +886,10 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * @return boolean - if page break is set
      */
     public boolean isPageBreak() {
-        final CTPPr ppr = getCTPPr();
+        final CTPPr ppr = getCTPPr(false);
+        if (ppr == null) {
+            return false;
+        }
         final CTOnOff ctPageBreak = ppr.isSetPageBreakBefore() ? 
ppr.getPageBreakBefore() : null;
         if (ctPageBreak == null) {
             return false;
@@ -1353,7 +1378,8 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      */
     @Override
     public boolean isWordWrapped() {
-        return getCTPPr().isSetWordWrap() && 
POIXMLUnits.parseOnOff(getCTPPr().getWordWrap());
+        CTPPr ppr = getCTPPr(false);
+        return ppr != null && ppr.isSetWordWrap() && 
POIXMLUnits.parseOnOff(ppr.getWordWrap());
     }
 
     /**
@@ -1390,7 +1416,10 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * @return the style of the paragraph
      */
     public String getStyle() {
-        CTPPr pr = getCTPPr();
+        CTPPr pr = getCTPPr(false);
+        if (pr == null) {
+            return null;
+        }
         CTString style = pr.isSetPStyle() ? pr.getPStyle() : null;
         return style != null ? style.getVal() : null;
     }
@@ -1411,7 +1440,10 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * a new instance.
      */
     private CTPBdr getCTPBrd(boolean create) {
-        CTPPr pr = getCTPPr();
+        CTPPr pr = getCTPPr(create);
+        if (pr == null) {
+            return null;
+        }
         CTPBdr ct = pr.isSetPBdr() ? pr.getPBdr() : null;
         if (create && ct == null) {
             ct = pr.addNewPBdr();
@@ -1424,7 +1456,7 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * return a new instance.
      */
     private CTSpacing getCTSpacing(boolean create) {
-        CTPPr pr = getCTPPr();
+        CTPPr pr = getCTPPr(create);
         CTSpacing ct = pr.getSpacing();
         if (create && ct == null) {
             ct = pr.addNewSpacing();
@@ -1437,7 +1469,10 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      * a new instance.
      */
     private CTInd getCTInd(boolean create) {
-        CTPPr pr = getCTPPr();
+        CTPPr pr = getCTPPr(create);
+        if (pr == null) {
+           return null;
+        }
         CTInd ct = pr.getInd();
         if (create && ct == null) {
             ct = pr.addNewInd();
@@ -1451,8 +1486,18 @@ public class XWPFParagraph implements IBodyElement, 
IRunBody, ISDTContents, Para
      */
     @Internal
     public CTPPr getCTPPr() {
-        return paragraph.getPPr() == null ? paragraph.addNewPPr()
-                : paragraph.getPPr();
+        return getCTPPr(true);
+    }
+
+    /**
+     * Get a <b>copy</b> of the currently used CTPPr. If none is used, return
+     * a new instance when create is true, or null when create is false.
+     *
+     * @param create create a new instance if none exists.
+     */
+    private CTPPr getCTPPr(final boolean create) {
+        return (paragraph.isSetPPr() || !create) ? paragraph.getPPr()
+                : paragraph.addNewPPr();
     }
 
 
diff --git a/poi-ooxml/src/test/java/org/apache/poi/xwpf/TestXWPFBugs.java 
b/poi-ooxml/src/test/java/org/apache/poi/xwpf/TestXWPFBugs.java
index ecf9d13601..4eefc3517a 100644
--- a/poi-ooxml/src/test/java/org/apache/poi/xwpf/TestXWPFBugs.java
+++ b/poi-ooxml/src/test/java/org/apache/poi/xwpf/TestXWPFBugs.java
@@ -16,10 +16,7 @@
 ==================================================================== */
 package org.apache.poi.xwpf;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import java.io.File;
@@ -42,10 +39,7 @@ import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.poifs.filesystem.Ole10Native;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFTable;
-import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.*;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
 import org.junit.jupiter.api.Test;
@@ -241,4 +235,17 @@ class TestXWPFBugs {
         XWPFTable xwpfTable = document.insertNewTbl(xmlCursor);
         xwpfTable.getRow(0).getCell(0).setText("Hello");
     }
+
+    @Test
+    void correctParagraphAlignment() throws IOException {
+        try (XWPFDocument document = new 
XWPFDocument(samples.openResourceAsStream("bug-paragraph-alignment.docx"))) {
+            XWPFParagraph centeredParagraph = document.getParagraphArray(0);
+            assertFalse(centeredParagraph.isAlignmentSet());
+            assertEquals(ParagraphAlignment.LEFT, 
centeredParagraph.getAlignment()); // LEFT is a fallback value here.
+
+            XWPFParagraph leftParagraph = document.getParagraphArray(1);
+            assertTrue(leftParagraph.isAlignmentSet());
+            assertEquals(ParagraphAlignment.LEFT, 
leftParagraph.getAlignment()); // LEFT is the real alignment value.
+        }
+    }
 }
diff --git 
a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java 
b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java
index 518734f4f6..2aaf6b1072 100644
--- 
a/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java
+++ 
b/poi-ooxml/src/test/java/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java
@@ -132,6 +132,7 @@ public final class TestXWPFParagraph {
             XWPFParagraph p = doc.createParagraph();
 
             assertEquals(STJc.LEFT.intValue(), p.getAlignment().getValue());
+            assertFalse(p.isAlignmentSet());
 
             CTP ctp = p.getCTP();
             CTPPr ppr = ctp.getPPr() == null ? ctp.addNewPPr() : ctp.getPPr();
@@ -139,9 +140,15 @@ public final class TestXWPFParagraph {
             CTJc align = ppr.addNewJc();
             align.setVal(STJc.CENTER);
             assertEquals(ParagraphAlignment.CENTER, p.getAlignment());
+            assertTrue(p.isAlignmentSet());
 
             p.setAlignment(ParagraphAlignment.BOTH);
             assertEquals(STJc.BOTH, ppr.getJc().getVal());
+            assertTrue(p.isAlignmentSet());
+
+            p.setAlignment(null);
+            assertEquals(STJc.LEFT.intValue(), p.getAlignment().getValue());
+            assertFalse(p.isAlignmentSet());
         }
     }
 
diff --git a/test-data/document/bug-paragraph-alignment.docx 
b/test-data/document/bug-paragraph-alignment.docx
new file mode 100644
index 0000000000..de4a468552
Binary files /dev/null and b/test-data/document/bug-paragraph-alignment.docx 
differ


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to