Сглаживание формы с использованием PDFClown вызывает исключение IndexOutOfBounds
Я использую PDFClown-0.2.0, чтобы сгладить этот файл PDF. Вот код, который у меня есть:
import org.pdfclown.documents.Document;
import org.pdfclown.files.File;
import org.pdfclown.files.SerializationModeEnum;
import org.pdfclown.tools.FormFlattener;
public class Sample {
public static void main(String args[]){
try {
File f = new File("label.pdf");
Document doc = f.getDocument();
FormFlattener formFlattener = new FormFlattener();
formFlattener.flatten(doc);
f.save(SerializationModeEnum.Standard);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Я следую инструкции, представленной на http://pdfclown.org/2014/09/12/waiting-for-pdf-clown-0-2-0-release/. Однако, когда я запускаю код, я получаю следующую ошибку:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at org.pdfclown.objects.PdfArray.get(PdfArray.java:314)
at org.pdfclown.documents.interaction.forms.FieldWidgets.get(FieldWidgets.java:135)
at org.pdfclown.documents.interaction.forms.FieldWidgets$1.next(FieldWidgets.java:380)
at org.pdfclown.documents.interaction.forms.FieldWidgets$1.next(FieldWidgets.java:1)
at org.pdfclown.tools.FormFlattener.flatten(FormFlattener.java:74)
at com.narvar.webservices.returns.retailers.Sample.main(Sample.java:18)
Что я делаю неправильно? Просто обратите внимание, что PDF был создан с использованием PDFBox, и я сделал поля формы только для чтения.
1 ответ
После отладки в коде это выглядит как ошибка PdfClown:
Iterator
вернулся org.pdfclown.documents.interaction.forms.FieldWidgets.iterator()
не распознает, что нижняя коллекция виджетов изменилась (стала меньше), и поэтому пытается читать за ее размер.
В деталях:
org.pdfclown.tools.FormFlattener.flatten(Document)
перебирает виджеты поля:
for(Widget widget : field.getWidgets())
но внутри этого цикла он удаляет текущий виджет из списка " Дети" текущего поля:
// Removing the field references relating the widget...
PdfDictionary fieldPartDictionary = widget.getBaseDataObject();
while (fieldPartDictionary != null)
{
[...]
kidsArray.remove(fieldPartDictionary.getReference());
[...]
}
Таким образом, коллекция, над которой внешний for
повторяет изменения. К сожалению Iterator
используется здесь не в курсе изменений в базовой коллекции
return new Iterator<Widget>()
{
/** Index of the next item. */
private int index = 0;
/** Collection size. */
private final int size = size();
@Override
public boolean hasNext( )
{return (index < size);}
@Override
public Widget next( )
{
if(!hasNext()) throw new NoSuchElementException();
return get(index++);
}
@Override
public void remove( )
{throw new UnsupportedOperationException();}
};
Поскольку вы видите, что он не просто не информирован и не проверяет саму базовую коллекцию, он даже имеет свое представление о размере коллекции, которая является размером коллекции в Iterator
поколение в size
,
Такой Iterator
реализация подходит для неизменяемых коллекций, которые могут быть реализованы в соответствии с архитектурой или контрактом. Но в данном случае я не вижу ни одной, архитектура, очевидно, позволяет изменять коллекцию, и нет никаких намеков на то, что рассматриваемый итератор может использоваться только для стабильных базовых коллекций.
Это должно быть исправлено.
Подход к решению
Решение может быть предпринято путем изменения FormFlattener.flatten
получить локальную копию виджетов и перебрать эту копию, например, заменив
for(Widget widget : field.getWidgets())
с
List<Widget> widgets = new ArrayList<Widget>(field.getWidgets());
for(Widget widget : widgets)