Skip to content

Commit

Permalink
Fix JabRef#621 and JabRef#669, along with some smaller changes to ser…
Browse files Browse the repository at this point in the history
…ialization

Also adds a lot of tests for serialization (and a few to the parser)
  • Loading branch information
tobiasdiez committed Feb 10, 2016
1 parent dc310c3 commit 0e6f137
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 55 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ to [sourceforge feature requests](https://sourceforge.net/p/jabref/features/) by
## [Unreleased]

### Changed
- Comments and preamble are serialized with capitalized first letter, i.e. `@Comment` instead of `@comment` and `@Preamble` instead of `@PREAMBLE`.
- Global sorting options and preferences are removed. Databases can still be sorted on save, but this is configured locally and stored in the file
- OvidImporter now also imports fields: doi, issn, language and keywords
- Implemented [#647](https://github.com/JabRef/jabref/issues/647): The preview can now be copied
Expand All @@ -26,6 +27,7 @@ to [sourceforge feature requests](https://sourceforge.net/p/jabref/features/) by


### Fixed
- Fixed [#621](https://github.com/JabRef/jabref/issues/621) and [#666](https://github.com/JabRef/jabref/issues/669) #669: Encoding and preamble now end with newline.
- Make BibTex parser more robust against missing newlines
- Fix bug that prevented the import of BibTex entries having only a key as content
- Fixed [#666](https://github.com/JabRef/jabref/issues/666): MS Office 2007 export is working again
Expand Down
65 changes: 35 additions & 30 deletions src/main/java/net/sf/jabref/exporter/BibDatabaseWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import net.sf.jabref.logic.CustomEntryTypesManager;
import net.sf.jabref.model.entry.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand All @@ -46,7 +45,11 @@ public class BibDatabaseWriter {

private static final Pattern REFERENCE_PATTERN = Pattern.compile("(#[A-Za-z]+#)"); // Used to detect string references in strings
private static final Log LOGGER = LogFactory.getLog(BibDatabaseWriter.class);
private static final String STRING_PREFIX = "@String";
private static final String COMMENT_PREFIX = "@Comment";
private static final String PREAMBLE_PREFIX = "@Preamble";
private BibEntry exceptionCause;
private boolean isFirstStringInType;

private static List<Comparator<BibEntry>> getSaveComparators(SavePreferences preferences, MetaData metaData) {

Expand Down Expand Up @@ -146,8 +149,6 @@ private static boolean shouldSaveInOriginalOrder(SavePreferences preferences, Me
return inOriginalOrder;
}

private BibtexString.Type previousStringType;

public SaveSession saveDatabase(BibDatabaseContext bibDatabaseContext, SavePreferences preferences)
throws SaveException {
return saveDatabase(bibDatabaseContext, preferences, false, false);
Expand Down Expand Up @@ -297,7 +298,9 @@ private void writeBibFileHeader(Writer out, Charset encoding) throws IOException

private void writeEpilogue(Writer writer, BibDatabase database) throws IOException {
if ((database.getEpilog() != null) && !(database.getEpilog().isEmpty())) {
writer.write(database.getEpilog());
writer.write(Globals.NEWLINE);
writer.write(database.getEpilog());
writer.write(Globals.NEWLINE);
}
}

Expand All @@ -314,13 +317,13 @@ private void writeMetaData(Writer out, MetaData metaData) throws IOException {

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(Globals.NEWLINE);
stringBuilder.append(Globals.NEWLINE);
List<String> orderedData = metaData.getData(key);
stringBuilder.append("@comment{").append(MetaData.META_FLAG).append(key).append(":");
stringBuilder.append(COMMENT_PREFIX + "{").append(MetaData.META_FLAG).append(key).append(":");
for (int j = 0; j < orderedData.size(); j++) {
stringBuilder.append(StringUtil.quote(orderedData.get(j), ";", '\\')).append(";");
}
stringBuilder.append("}");
stringBuilder.append(Globals.NEWLINE);

out.write(stringBuilder.toString());
}
Expand All @@ -331,18 +334,14 @@ private void writeMetaData(Writer out, MetaData metaData) throws IOException {
StringBuffer sb = new StringBuffer();
// write version first
sb.append(Globals.NEWLINE);
sb.append(Globals.NEWLINE);
sb.append("@comment{").append(MetaData.META_FLAG).append(MetaData.GROUPSVERSION).append(":");
sb.append(COMMENT_PREFIX + "{").append(MetaData.META_FLAG).append(MetaData.GROUPSVERSION).append(":");
sb.append("" + VersionHandling.CURRENT_VERSION + ";");
sb.append("}");

out.write(sb.toString());
sb.append(Globals.NEWLINE);

// now write actual groups
sb = new StringBuffer();
sb.append(Globals.NEWLINE);
sb.append(Globals.NEWLINE);
sb.append("@comment{").append(MetaData.META_FLAG).append(MetaData.GROUPSTREE).append(":");
sb.append(COMMENT_PREFIX + "{").append(MetaData.META_FLAG).append(MetaData.GROUPSTREE).append(":");
sb.append(Globals.NEWLINE);
// GroupsTreeNode.toString() uses "\n" for separation
StringTokenizer tok = new StringTokenizer(groupsRoot.getTreeAsString(), Globals.NEWLINE);
Expand All @@ -353,14 +352,15 @@ private void writeMetaData(Writer out, MetaData metaData) throws IOException {
sb.append(Globals.NEWLINE);
}
sb.append("}");
sb.append(Globals.NEWLINE);
out.write(sb.toString());
}
}

private void writePreamble(Writer fw, String preamble) throws IOException {
if (preamble != null) {
fw.write(Globals.NEWLINE);
fw.write("@PREAMBLE{");
fw.write(PREAMBLE_PREFIX + "{");
fw.write(preamble);
fw.write('}' + Globals.NEWLINE);
}
Expand All @@ -377,6 +377,10 @@ private void writeString(Writer fw, BibtexString bs, Map<String, BibtexString> r
return;
}

if(isFirstStringInType) {
fw.write(Globals.NEWLINE);
}

// Then we go through the string looking for references to other strings. If we find references
// to strings that we will write, but still haven't, we write those before proceeding. This ensures
// that the string order will be acceptable for BibTeX.
Expand All @@ -393,18 +397,13 @@ private void writeString(Writer fw, BibtexString bs, Map<String, BibtexString> r
}
}

if (previousStringType != bs.getType()) {
fw.write(Globals.NEWLINE);
previousStringType = bs.getType();
}

StringBuilder suffixSB = new StringBuilder();
for (int i = maxKeyLength - bs.getName().length(); i > 0; i--) {
suffixSB.append(' ');
}
String suffix = suffixSB.toString();

fw.write("@String { " + bs.getName() + suffix + " = ");
fw.write(STRING_PREFIX + "{" + bs.getName() + suffix + " = ");
if (bs.getContent().isEmpty()) {
fw.write("{}");
} else {
Expand All @@ -418,7 +417,7 @@ private void writeString(Writer fw, BibtexString bs, Map<String, BibtexString> r
}
}

fw.write(" }" + Globals.NEWLINE);
fw.write("}" + Globals.NEWLINE);
}

/**
Expand All @@ -430,7 +429,6 @@ private void writeString(Writer fw, BibtexString bs, Map<String, BibtexString> r
* @throws IOException If anything goes wrong in writing.
*/
private void writeStrings(Writer fw, BibDatabase database) throws IOException {
previousStringType = BibtexString.Type.AUTHOR;
List<BibtexString> strings = database.getStringKeySet().stream().map(database::getString).collect(
Collectors.toList());
strings.sort(new BibtexStringComparator(true));
Expand All @@ -443,23 +441,30 @@ private void writeStrings(Writer fw, BibDatabase database) throws IOException {
}

for (BibtexString.Type t : BibtexString.Type.values()) {
isFirstStringInType = true;
for (BibtexString bs : strings) {
if (remaining.containsKey(bs.getName()) && (bs.getType() == t)) {
writeString(fw, bs, remaining, maxKeyLength);
isFirstStringInType = false;
}
}
}
}

private void writeTypeDefinitions(Writer writer, Map<String, EntryType> types) throws IOException {
if (!types.isEmpty()) {
for (Map.Entry<String, EntryType> stringBibtexEntryTypeEntry : types.entrySet()) {
EntryType type = stringBibtexEntryTypeEntry.getValue();
if (type instanceof CustomEntryType) {
CustomEntryType customType = (CustomEntryType) type;
CustomEntryTypesManager.save(customType, writer);
writer.write(Globals.NEWLINE);
}
for (EntryType type : types.values()) {
if (type instanceof CustomEntryType) {
CustomEntryType customType = (CustomEntryType) type;
writer.write(Globals.NEWLINE);
writer.write(COMMENT_PREFIX + "{");
writer.write(CustomEntryType.ENTRYTYPE_FLAG);
writer.write(customType.getName());
writer.write(": req[");
writer.write(customType.getRequiredFieldsString());
writer.write("] opt[");
writer.write(String.join(";", customType.getOptionalFields()));
writer.write("]}");
writer.write(Globals.NEWLINE);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ private ParserResult parseFileContent() throws IOException {

if ("preamble".equals(entryType)) {
database.setPreamble(parsePreamble());
// Consume new line which signals end of preamble
skipOneNewline();
// the preamble is saved verbatim anyways, so the text read so far can be dropped
dumpTextReadSoFarToString();
} else if ("string".equals(entryType)) {
Expand All @@ -187,7 +189,7 @@ private ParserResult parseFileContent() throws IOException {
}

private void parseRemainingContent() {
database.setEpilog(dumpTextReadSoFarToString());
database.setEpilog(dumpTextReadSoFarToString().trim());
}

private void parseAndAddEntry(String type) {
Expand Down Expand Up @@ -465,7 +467,10 @@ private BibtexString parseString() throws IOException {
String content = parseFieldContent(name);
LOGGER.debug("Now I'm going to consume a }");
consume('}', ')');
// Consume new line which signals end of entry
skipOneNewline();
LOGGER.debug("Finished string parsing.");

String id = IdGenerator.next();
return new BibtexString(id, name, content);
}
Expand Down
12 changes: 0 additions & 12 deletions src/main/java/net/sf/jabref/logic/CustomEntryTypesManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,6 @@ public static void saveCustomEntryTypes(JabRefPreferences prefs) {
prefs.purgeCustomEntryTypes(number);
}

public static void save(CustomEntryType entry, Writer out) throws IOException {
out.write(Globals.NEWLINE + Globals.NEWLINE);
out.write("@comment{");
out.write(CustomEntryType.ENTRYTYPE_FLAG);
out.write(entry.getName());
out.write(": req[");
out.write(entry.getRequiredFieldsString());
out.write("] opt[");
out.write(String.join(";", entry.getOptionalFields()));
out.write("]}");
}

public static CustomEntryType parseEntryType(String comment) {
try {
String rest;
Expand Down
Loading

0 comments on commit 0e6f137

Please # to comment.