Skip to content

Conversation

turhantolgaunal
Copy link
Contributor

@turhantolgaunal turhantolgaunal commented Sep 9, 2025

Closes #12642

The study.yml is refactored to a new format to implement SEMVER versioning, variable 'databases' is renamed to 'catalogues' for UI consistency.

In the course of working on this draft pull request the query structure is planned to be enhanced to support multiple query formats including catalog-specific variations.

Steps to test

The study.yml file created when a new slr is started should be in a new format and slr search should function as intended.
New format is:
version: 2.0
authors:

  • author
    title: title
    research-questions:
  • question
    queries:
  • query: (author="author" AND title="title")
    description: null
    lucene: null
    catalogue-specific: null
    catalogues:
  • name: ArXiv
    enabled: true
    metadata:
    notes: null
    created-date: null
    last-modified: null

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • I manually tested my changes in running JabRef (always required)
  • I added JUnit tests for changes (if applicable)
  • [/] I added screenshots in the PR description (if change is visible to the user)
  • [/] I described the change in CHANGELOG.md in a way that is understandable for the average user (if change is visible to the user)
  • I checked the user documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request updating file(s) in https://github.com/JabRef/user-documentation/tree/main/en.

@turhantolgaunal turhantolgaunal changed the title Reformatted database variable to catalogue New study.yml format Sep 9, 2025
@@ -8,7 +8,7 @@
import org.jabref.logic.importer.ImportFormatPreferences;
import org.jabref.logic.importer.ImporterPreferences;
import org.jabref.model.study.Study;
import org.jabref.model.study.StudyDatabase;
import org.jabref.model.study.StudyCatalog;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import statement for StudyCatalog is correct, but the patch does not address the need to use JavaFX ObservableLists for better practice in managing lists in JavaFX applications.

@@ -92,14 +92,14 @@ void studyConstructorFillsDatabasesCorrectly(@TempDir Path tempDir) {
}

private ManageStudyDefinitionViewModel getManageStudyDefinitionViewModel(Path tempDir) {
List<StudyDatabase> databases = List.of(
new StudyDatabase("ACM Portal", true));
List<StudyCatalog> catalogs = List.of(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code uses List.of() which is correct, but it does not utilize JavaFX ObservableLists, which is considered best practice for managing lists in JavaFX applications.

StudyYamlParser studyYAMLParser = new StudyYamlParser();
studyYAMLParser.writeStudyYamlFile(newStudy, studyRepositoryRoot.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
StudyYamlService studyYamlService = new StudyYamlService();
studyYamlService.writeStudyYamlFile(newStudy, studyRepositoryRoot.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method writeStudyYamlFile should ensure it does not return null. If it does, it should use java.util.Optional to handle potential null values.


if (CURRENT_VERSION.equals(version)) {
// Already current version, read the file normally
try (InputStream fileInputStream = Files.newInputStream(studyYamlFile)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try block covers the entire method, which is against best practices. It should cover as few statements as possible to minimize the scope of potential exceptions.

}

@JsonSetter("metadata")
public void setMetadata(Optional<StudyMetadata> metadata) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method setMetadata should not accept null values. Consider using Optional.ofNullable to handle potential null inputs gracefully.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing Optionals as Arguments is rarely a good, especially if the nextline reads if the optional itself is checked for null in the next line. This seems not intended. Use Optionals as return types, not as fields or arguments.

@turhantolgaunal turhantolgaunal marked this pull request as ready for review September 24, 2025 17:30
Study study;
try {
study = new StudyYamlParser().parseStudyYamlFile(studyDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
study = new StudyYamlService().parseStudyYamlFile(studyDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try block covers too many statements, which is against best practices. It should only cover the statement that might throw the exception to improve readability and maintainability.

private Optional<String> getVersionFromFile(Path studyYamlFile) throws IOException {
ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());

try (InputStream fileInputStream = Files.newInputStream(studyYamlFile)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try block covers multiple statements, which is not recommended. It should cover as few statements as possible to isolate potential exceptions.

*/
public Study parseStudyYamlFile(Path studyYamlFile) throws IOException {
if (needsMigration(studyYamlFile)) {
Study migratedStudy = StudyYamlMigrator.migrateStudyYamlFile(studyYamlFile);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method migrateStudyYamlFile should not return null. It should return an Optional or throw an exception if migration fails.

@Test
void parseStudyFileSuccessfully() throws IOException {
Study study = new StudyYamlParser().parseStudyYamlFile(testDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
Study study = new StudyYamlService().parseStudyYamlFile(testDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method parseStudyYamlFile should throw a generic Exception instead of IOException to adhere to the instruction of using 'throws Exception' in the method declaration.

URL studyDefinition = StudyYamlParser.class.getResource("study-jabref-5.7.yml");
Study study = new StudyYamlParser().parseStudyYamlFile(Path.of(studyDefinition.toURI()));
URL studyDefinition = StudyYamlService.class.getResource("study-jabref-5.7.yml");
Study study = new StudyYamlService().parseStudyYamlFile(Path.of(studyDefinition.toURI()));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method parseStudyYamlFile should throw a generic Exception instead of IOException to adhere to the instruction of using 'throws Exception' in the method declaration.

/**
* Creates metadata by extracting information from file and existing data
*/
private StudyMetadata createMetadata(Path studyYamlFile, V1StudyFormat oldStudy) throws IOException {
Copy link
Member

@calixtus calixtus Sep 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise here: Annotate with @NonNull

Comment on lines +146 to +148
} else if (queryObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> queryMap = (Map<String, Object>) queryObj;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else if (queryObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> queryMap = (Map<String, Object>) queryObj;
} else if (queryObj instanceof Map<String, Object> queryMap) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this works with SuppressWarnings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives a unsafe casting error though

@turhantolgaunal turhantolgaunal marked this pull request as draft September 27, 2025 11:02
@turhantolgaunal turhantolgaunal marked this pull request as ready for review September 29, 2025 16:31
* Generate notes for the migration
*/
private String generateMigrationNotes(V1StudyFormat oldStudy) {
StringJoiner notes = new StringJoiner(" ");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringJoiner is used correctly here, but ensure that it is used consistently throughout the codebase for string concatenation to maintain consistency.

Copy link

trag-bot bot commented Sep 29, 2025

@trag-bot didn't find any issues in the code! ✅✨

assertEquals(expectedStudy, study);
}

@Test
void writeStudyFileSuccessfully() throws IOException {
new StudyYamlParser().writeStudyYamlFile(expectedStudy, testDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
Study study = new StudyYamlParser().parseStudyYamlFile(testDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
new StudyYamlService().writeStudyYamlFile(expectedStudy, testDirectory.resolve(StudyRepository.STUDY_DEFINITION_FILE_NAME));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method writeStudyYamlFile should throw a generic Exception instead of IOException to adhere to the principle of letting JUnit handle exceptions in tests.

@@ -58,8 +58,8 @@ void readsJabRef57StudySuccessfully() throws URISyntaxException, IOException {
// If the field is "just" removed from the datamodel, one gets following exception:
// com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "last-search-date" (class org.jabref.model.study.Study), not marked as ignorable (5 known properties: "authors", "research-questions", "queries", "title", "databases"])
// This tests ensures that this exception does not occur
URL studyDefinition = StudyYamlParser.class.getResource("study-jabref-5.7.yml");
Study study = new StudyYamlParser().parseStudyYamlFile(Path.of(studyDefinition.toURI()));
URL studyDefinition = StudyYamlService.class.getResource("study-jabref-5.7.yml");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method readsJabRef57StudySuccessfully should throw a generic Exception instead of IOException and URISyntaxException to adhere to the principle of letting JUnit handle exceptions in tests.

assertEquals("Database2", catalogs.get(1).getName());

// Third database explicitly disabled
assertFalse(catalogs.get(2).isEnabled());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code uses assertFalse to check a boolean condition. It should assert the contents of objects using assertEquals for better clarity and precision.

@jabref-machine
Copy link
Collaborator

Your code currently does not meet JabRef's code guidelines. We use OpenRewrite to ensure "modern" Java coding practices. You can see which checks are failing by locating the box "Some checks were not successful" on the pull request page. To see the test output, locate "Source Code Tests / OpenRewrite (pull_request)" and click on it.

The issues found can be automatically fixed. Please execute the gradle task rewriteRun from the rewrite group of the Gradle Tool window in IntelliJ, then check the results, commit, and push.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New study.yml format
3 participants