Skip to content

Commit 7ec4c7e

Browse files
authored
Fix NegativeArraySizeException (#8270)
* Fix NegativeArraySizeException * More tests * Make Math.max more readable * Add saving finished notification
1 parent 7aaf5e2 commit 7ec4c7e

File tree

8 files changed

+116
-23
lines changed

8 files changed

+116
-23
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
2626
- We added an option to search the available citation styles by name in the preferences [#8108](https://github.com/JabRef/jabref/issues/8108)
2727
- We added an option to generate bib-entries from ID through a popover in the toolbar. [#4183](https://github.com/JabRef/jabref/issues/4183)
2828
- We added a menu option in the right click menu of the main table tabs to display the library properties. [#6527](https://github.com/JabRef/jabref/issues/6527)
29+
- When a `.bib` file ("library") was saved successfully, a notification is shown
2930

3031
### Changed
3132

@@ -66,6 +67,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
6667
- We fixed an issue where importing PDFs resulted in an uncaught exception [#8143](https://github.com/JabRef/jabref/issues/8143)
6768
- We fixed "The library has been modified by another program" showing up when line breaks change [#4877](https://github.com/JabRef/jabref/issues/4877)
6869
- The default directory of the "LaTeX Citations" tab is now the directory of the currently opened database (and not the directory chosen at the last open file dialog or the last database save) [koppor#538](https://github.com/koppor/jabref/issues/538)
70+
- When writing a bib file, the `NegativeArraySizeException` should not occur [#8231](https://github.com/JabRef/jabref/issues/8231) [#8265](https://github.com/JabRef/jabref/issues/8265)
6971
- We fixed an issue where right-clicking on a tab and selecting close will close the focused tab even if it is not the tab we right-clicked [#8193](https://github.com/JabRef/jabref/pull/8193)
7072
- We fixed an issue where selecting a citation style in the preferences would sometimes produce an exception [#7860](https://github.com/JabRef/jabref/issues/7860)
7173
- We fixed an issue where an exception would occur when clicking on a DOI link in the preview pane [#7706](https://github.com/JabRef/jabref/issues/7706)

src/main/java/org/jabref/gui/DialogService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ Optional<ButtonType> showCustomButtonDialogAndWait(Alert.AlertType type, String
215215
<V> Optional<ButtonType> showBackgroundProgressDialogAndWait(String title, String content, StateManager stateManager);
216216

217217
/**
218-
* Notify the user in an non-blocking way (i.e., in form of toast in a snackbar).
218+
* Notify the user in a non-blocking way (i.e., in form of toast in a snackbar).
219219
*
220220
* @param message the message to show.
221221
*/

src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ private boolean save(Path targetPath, SaveDatabaseMode mode) {
214214
libraryTab.getUndoManager().markUnchanged();
215215
libraryTab.resetChangedProperties();
216216
}
217+
dialogService.notify(Localization.lang("Library saved"));
217218
return success;
218219
} catch (SaveException ex) {
219220
LOGGER.error(String.format("A problem occurred when trying to save the file %s", targetPath), ex);

src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ private void writeRequiredFieldsFirstRemainingFieldsSecond(BibEntry entry, BibWr
9393

9494
Set<Field> written = new HashSet<>();
9595
written.add(InternalField.KEY_FIELD);
96-
int indentation = getLengthOfLongestFieldName(entry);
96+
final int indent = getLengthOfLongestFieldName(entry);
9797

9898
Optional<BibEntryType> type = entryTypesManager.enrich(entry.getType(), bibDatabaseMode);
9999
if (type.isPresent()) {
@@ -106,7 +106,7 @@ private void writeRequiredFieldsFirstRemainingFieldsSecond(BibEntry entry, BibWr
106106
.collect(Collectors.toList());
107107

108108
for (Field field : requiredFields) {
109-
writeField(entry, out, field, indentation);
109+
writeField(entry, out, field, indent);
110110
}
111111

112112
// Then optional fields
@@ -118,7 +118,7 @@ private void writeRequiredFieldsFirstRemainingFieldsSecond(BibEntry entry, BibWr
118118
.collect(Collectors.toList());
119119

120120
for (Field field : optionalFields) {
121-
writeField(entry, out, field, indentation);
121+
writeField(entry, out, field, indent);
122122
}
123123

124124
written.addAll(requiredFields);
@@ -131,7 +131,7 @@ private void writeRequiredFieldsFirstRemainingFieldsSecond(BibEntry entry, BibWr
131131
.collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName))));
132132

133133
for (Field field : remainingFields) {
134-
writeField(entry, out, field, indentation);
134+
writeField(entry, out, field, indent);
135135
}
136136

137137
// Finally, end the entry.
@@ -151,12 +151,13 @@ private void writeKeyField(BibEntry entry, BibWriter out) throws IOException {
151151
* @param field the field
152152
* @throws IOException In case of an IO error
153153
*/
154-
private void writeField(BibEntry entry, BibWriter out, Field field, int indentation) throws IOException {
154+
private void writeField(BibEntry entry, BibWriter out, Field field, int indent) throws IOException {
155155
Optional<String> value = entry.getField(field);
156156
// only write field if it is not empty
157157
// field.ifPresent does not work as an IOException may be thrown
158158
if (value.isPresent() && !value.get().trim().isEmpty()) {
159-
out.write(" " + getFormattedFieldName(field, indentation));
159+
out.write(" ");
160+
out.write(getFormattedFieldName(field, indent));
160161
try {
161162
out.write(fieldWriter.write(field, value.get()));
162163
} catch (InvalidFieldValueException ex) {
@@ -166,7 +167,7 @@ private void writeField(BibEntry entry, BibWriter out, Field field, int indentat
166167
}
167168
}
168169

169-
private int getLengthOfLongestFieldName(BibEntry entry) {
170+
static int getLengthOfLongestFieldName(BibEntry entry) {
170171
Predicate<Field> isNotCitationKey = field -> !InternalField.KEY_FIELD.equals(field);
171172
return entry.getFields()
172173
.stream()
@@ -177,7 +178,7 @@ private int getLengthOfLongestFieldName(BibEntry entry) {
177178
}
178179

179180
/**
180-
* Get display version of a entry field.
181+
* Get display version of an entry field.
181182
* <p>
182183
* BibTeX is case-insensitive therefore there is no difference between: howpublished, HOWPUBLISHED, HowPublished, etc.
183184
* <p>
@@ -188,8 +189,8 @@ private int getLengthOfLongestFieldName(BibEntry entry) {
188189
* @param field The name of the field.
189190
* @return The display version of the field name.
190191
*/
191-
private String getFormattedFieldName(Field field, int intention) {
192+
static String getFormattedFieldName(Field field, int indent) {
192193
String fieldName = field.getName();
193-
return fieldName.toLowerCase(Locale.ROOT) + StringUtil.repeatSpaces(intention - fieldName.length()) + " = ";
194+
return fieldName.toLowerCase(Locale.ROOT) + StringUtil.repeatSpaces(indent - fieldName.length()) + " = ";
194195
}
195196
}

src/main/java/org/jabref/model/strings/StringUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public static String join(String[] strings, String separator, int from, int to)
138138
return "";
139139
}
140140

141-
int updatedFrom = Math.max(from, 0);
141+
int updatedFrom = Math.max(0, from);
142142
int updatedTo = Math.min(strings.length, to);
143143

144144
StringBuilder stringBuilder = new StringBuilder();
@@ -600,7 +600,7 @@ public static String replaceSpecialCharacters(String s) {
600600
* @return String with n spaces
601601
*/
602602
public static String repeatSpaces(int n) {
603-
return repeat(n, ' ');
603+
return repeat(Math.max(0, n), ' ');
604604
}
605605

606606
/**

src/main/resources/l10n/JabRef_en.properties

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -753,13 +753,11 @@ Save\ before\ closing=Save before closing
753753

754754
Save\ library=Save library
755755
Save\ library\ as...=Save library as...
756-
757-
Saved\ selected\ to\ '%0'.=Saved selected to '%0'.
758-
759756
Saving=Saving
760757
Saving\ all\ libraries...=Saving all libraries...
761-
762758
Saving\ library=Saving library
759+
Library\ saved=Library saved
760+
Saved\ selected\ to\ '%0'.=Saved selected to '%0'.
763761

764762
Search=Search
765763

src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.Collection;
88
import java.util.List;
99
import java.util.Set;
10+
import java.util.stream.Stream;
1011

1112
import org.jabref.logic.exporter.BibWriter;
1213
import org.jabref.logic.importer.ImportFormatPreferences;
@@ -18,14 +19,19 @@
1819
import org.jabref.model.entry.BibEntryTypesManager;
1920
import org.jabref.model.entry.LinkedFile;
2021
import org.jabref.model.entry.field.Field;
22+
import org.jabref.model.entry.field.FieldFactory;
2123
import org.jabref.model.entry.field.StandardField;
24+
import org.jabref.model.entry.types.EntryTypeFactory;
2225
import org.jabref.model.entry.types.StandardEntryType;
2326
import org.jabref.model.entry.types.UnknownEntryType;
2427
import org.jabref.model.util.DummyFileUpdateMonitor;
2528
import org.jabref.model.util.FileUpdateMonitor;
2629

2730
import org.junit.jupiter.api.BeforeEach;
2831
import org.junit.jupiter.api.Test;
32+
import org.junit.jupiter.params.ParameterizedTest;
33+
import org.junit.jupiter.params.provider.Arguments;
34+
import org.junit.jupiter.params.provider.MethodSource;
2935
import org.mockito.Answers;
3036

3137
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -464,7 +470,7 @@ void monthFieldSpecialSyntax() throws IOException {
464470
Collection<BibEntry> entries = result.getDatabase().getEntries();
465471
BibEntry entry = entries.iterator().next();
466472

467-
// modify month field
473+
// check month field
468474
Set<Field> fields = entry.getFields();
469475
assertTrue(fields.contains(StandardField.MONTH));
470476
assertEquals("#mar#", entry.getField(StandardField.MONTH).get());
@@ -475,6 +481,51 @@ void monthFieldSpecialSyntax() throws IOException {
475481
assertEquals(bibtexEntry, stringWriter.toString());
476482
}
477483

484+
@Test
485+
void customTypeCanBewritten() throws IOException {
486+
// @formatter:off
487+
String bibtexEntry = "@reference{Broecker1984,\n" +
488+
"title = {International Center of Photography},\n" +
489+
"subtitle = {Encyclopedia of Photography},\n" +
490+
"editor = {Broecker, William L.},\n" +
491+
"date = {1984},\n" +
492+
"eprint = {305515791},\n" +
493+
"eprinttype = {scribd},\n" +
494+
"isbn = {0-517-55271-X},\n" +
495+
"keywords = {g:photography, p:positive, c:silver, m:albumen, c:pigment, m:carbon, g:reference, c:encyclopedia},\n" +
496+
"location = {New York},\n" +
497+
"pagetotal = {678},\n" +
498+
"publisher = {Crown},\n" +
499+
"}\n";
500+
// @formatter:on
501+
502+
// read in bibtex string
503+
ParserResult result = new BibtexParser(importFormatPreferences, fileMonitor).parse(new StringReader(bibtexEntry));
504+
Collection<BibEntry> entries = result.getDatabase().getEntries();
505+
BibEntry entry = entries.iterator().next();
506+
507+
entry.setField(FieldFactory.parseField("location"), "NY");
508+
509+
// write out bibtex string
510+
bibEntryWriter.write(entry, bibWriter, BibDatabaseMode.BIBTEX);
511+
512+
String expected = "@Reference{Broecker1984," + OS.NEWLINE +
513+
" date = {1984}," + OS.NEWLINE +
514+
" editor = {Broecker, William L.}," + OS.NEWLINE +
515+
" eprint = {305515791}," + OS.NEWLINE +
516+
" eprinttype = {scribd}," + OS.NEWLINE +
517+
" isbn = {0-517-55271-X}," + OS.NEWLINE +
518+
" keywords = {g:photography, p:positive, c:silver, m:albumen, c:pigment, m:carbon, g:reference, c:encyclopedia}," + OS.NEWLINE +
519+
" location = {NY}," + OS.NEWLINE +
520+
" pagetotal = {678}," + OS.NEWLINE +
521+
" publisher = {Crown}," + OS.NEWLINE +
522+
" subtitle = {Encyclopedia of Photography}," + OS.NEWLINE +
523+
" title = {International Center of Photography}," + OS.NEWLINE +
524+
"}" + OS.NEWLINE;
525+
526+
assertEquals(expected, stringWriter.toString());
527+
}
528+
478529
@Test
479530
void constantMonthApril() throws Exception {
480531
BibEntry entry = new BibEntry(StandardEntryType.Misc)
@@ -713,6 +764,38 @@ void testSerializeAll() throws IOException {
713764
// @formatter:on
714765

715766
assertEquals(expected1 + OS.NEWLINE + expected2, output);
767+
}
768+
769+
static Stream<Arguments> testGetFormattedFieldNameData() {
770+
return Stream.of(
771+
Arguments.of(" = ", "", 0),
772+
Arguments.of("a = ", "a", 0),
773+
Arguments.of(" = ", "", 2),
774+
Arguments.of("a = ", "a", 2),
775+
Arguments.of("abc = ", "abc", 2),
776+
Arguments.of("abcdef = ", "abcdef", 6)
777+
);
778+
}
779+
780+
@ParameterizedTest
781+
@MethodSource("testGetFormattedFieldNameData")
782+
void testGetFormattedFieldName(String expected, String fieldName, int indent) {
783+
Field field = FieldFactory.parseField(fieldName);
784+
assertEquals(expected, bibEntryWriter.getFormattedFieldName(field, indent));
785+
}
786+
787+
static Stream<Arguments> testGetLengthOfLongestFieldNameData() {
788+
return Stream.of(
789+
Arguments.of(1, new BibEntry().withField(FieldFactory.parseField("t"), "t")),
790+
Arguments.of(5, new BibEntry(EntryTypeFactory.parse("reference"))
791+
.withCitationKey("Broecker1984")
792+
.withField(StandardField.TITLE, "International Center of Photography}"))
793+
);
794+
}
716795

796+
@ParameterizedTest
797+
@MethodSource("testGetLengthOfLongestFieldNameData")
798+
void testGetLengthOfLongestFieldName(int expected, BibEntry entry) {
799+
assertEquals(expected, bibEntryWriter.getLengthOfLongestFieldName(entry));
717800
}
718801
}

src/test/java/org/jabref/model/strings/StringUtilTest.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,19 @@ void replaceSpecialCharactersWithNonNormalizedUnicode() {
308308
assertEquals("Modele", StringUtil.replaceSpecialCharacters("Modèle"));
309309
}
310310

311-
@Test
312-
void testRepeatSpaces() {
313-
assertEquals("", StringUtil.repeatSpaces(0));
314-
assertEquals(" ", StringUtil.repeatSpaces(1));
315-
assertEquals(" ", StringUtil.repeatSpaces(7));
311+
static Stream<Arguments> testRepeatSpacesData() {
312+
return Stream.of(
313+
Arguments.of("", -1),
314+
Arguments.of("", 0),
315+
Arguments.of(" ", 1),
316+
Arguments.of(" ", 7)
317+
);
318+
}
319+
320+
@ParameterizedTest
321+
@MethodSource("testRepeatSpacesData")
322+
void testRepeatSpaces(String result, int count) {
323+
assertEquals(result, StringUtil.repeatSpaces(count));
316324
}
317325

318326
@Test

0 commit comments

Comments
 (0)