Skip to Main Content

Java Programming

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Apache POI Word support - workaround for a write bug

807605Jul 11 2007 — edited Jul 11 2007
Hi all,

Just finished battling with the bugs in POI HWPF component. When searching forums, I found more questions than answers so I wanted to save others a significant effort until POI guys implement all the fixes.

Basically, the synopsis is, all the delete() methods are broken and replacing a string with a string of a different size corrupts the document. But insertAfter and insertBefore methods are mostly working.

I did not want to add a method to their class, because it will probably be overwritten. On the other hand, it is unknown when it will be fixed. Therefore, I had to go via reflection.

Here's the method, just attach it to your class and it's ready to use:
	/**
	 * Replaces text in the paragraph by a specified new text.
	 * @param r	A paragraph to replace.
	 * @param newText	A new text.
	 * @throws Exception	if anything goes wrong
	 */
	protected void setParagraphText(Paragraph r, String newText) throws Exception {
		int length = r.text().length() - 1;
		Class clRange = Range.class;
		Field fldText = clRange.getDeclaredField("_text");
		fldText.setAccessible(true);
		Field fldTextEnd = clRange.getDeclaredField("_textEnd");
		fldTextEnd.setAccessible(true);
		Field fldStart = clRange.getDeclaredField("_start");
		fldStart.setAccessible(true);
		List textPieces = (List)fldText.get(r);
		int _textEnd = fldTextEnd.getInt(r);
		TextPiece t = (TextPiece)textPieces.get(_textEnd - 1);
		StringBuffer sb = t.getStringBuffer();
		int offset = fldStart.getInt(r);
		int diff = newText.length() - length;
		if (diff <= 0) {
			// delete doesn't work properly yet, corrupting the documents.
			// Therefore a quick and ugly workaround is to pad the new text with spaces 
			for (int i = 0; i < -diff; i++)
				newText += " ";
			sb.replace(offset, offset + length, newText);
		} else {
			// when the new text is longer, the old one must be replaced
			// character by character, and the difference is added using
			// insertAfter method
			if (r.isInTable()) {
				// more obstacles when working with tables though.
				// Not only the regular insertAfter does not work, 
				// but also insertAfter called from a cell overruns cell delimiters.
				// Needless to say, getTable(r) does not return the required table.
				// Fortunately, there's a workaround
				TableIterator ti = new TableIterator(range);
				TableCell tc;
				while (ti.hasNext()) {
					Table tbl = ti.next();
					for (int i = 0; i < tbl.numRows(); i++) { 
						TableRow tr = tbl.getRow(i);
						for (int j = 0; j < tr.numCells(); j++) {
							tc = tr.getCell(j);
							if (tc.text().startsWith(sb.substring(offset, offset + length))) {
								sb.replace(offset, offset + length, 
										newText.substring(newText.length() - length));
								// only like this, otherwise cell delimiter will be run over
								tc.insertBefore(newText.substring(0, newText.length() - length)); 
								return;
							}
						}
					}
				}
				sb.replace(offset, offset + length, newText.substring(0, length));
			} else {
				sb.replace(offset, offset + length, newText.substring(0, length));
				r.insertAfter(newText.substring(length));
			}
		}
			
	}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Aug 8 2007
Added on Jul 11 2007
0 comments
309 views