Skip to content

fix(occurrence): fix for #526#528

Merged
djtfmartin merged 1 commit into
devfrom
fix/526-ext-duplicate-keys
Jun 23, 2026
Merged

fix(occurrence): fix for #526#528
djtfmartin merged 1 commit into
devfrom
fix/526-ext-duplicate-keys

Conversation

@djtfmartin

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses occurrence download failures where duplicate normalized extension field names caused extension CSV writing to fail (issue #526), leading to empty or missing download archives. It updates DownloadDwcaActor to tolerate duplicates and adjusts exception propagation, and adds a unit test around extension-field normalization.

Changes:

  • Handle duplicate normalized extension keys when building extension record maps (avoid Collectors.toMap duplicate-key failure).
  • Replace Guava Throwables.propagate usage with RuntimeException wrapping in the actor.
  • Add a unit test for toExtensionRecord normalization behavior, plus akka-testkit for test support.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
occurrence-download/src/main/java/org/gbif/occurrence/download/file/dwca/akka/DownloadDwcaActor.java Avoids failure on duplicate normalized extension keys; adjusts exception propagation; adds local normalization helper.
occurrence-download/src/test/java/org/gbif/occurrence/download/file/dwca/akka/DownloadDwcaActorTest.java Adds coverage for extension record normalization and duplicate-key handling.
occurrence-download/pom.xml Adds akka-testkit as a test dependency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@djtfmartin
djtfmartin force-pushed the fix/526-ext-duplicate-keys branch from 0c992c5 to fe4560e Compare June 23, 2026 12:14
@djtfmartin
djtfmartin requested a review from Copilot June 23, 2026 12:18
@djtfmartin
djtfmartin force-pushed the fix/526-ext-duplicate-keys branch from bf4b229 to f1a9d07 Compare June 23, 2026 12:21
String key = normalizeFieldName(HiveColumns.columnFor(e.getKey()));
String val = e.getValue();
if (normalized.containsKey(key)) {
// Keep the first value, but log the duplicate for diagnostics

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we need to return both terms instead of taking the first one so we download the extension as it is originally. Both are valid terms, they could have different values even if it were weird. I think this is what we do in big downloads(would be good to check)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

How can we do this without changing the headers in downloads to include some sort of prefix (and potentially breaking third party scripts) ?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

occurrence-download/src/test/java/org/gbif/occurrence/download/file/dwca/akka/DownloadDwcaActorTest.java:79

  • The ActorSystem created for this test is never terminated, which can leak threads and cause the test JVM to hang. Ensure it’s shut down (ideally in a finally/@AfterEach).
}

expected.put(DcElement.source.simpleName().toLowerCase(), "US National Herbarium, Department of Botany, NMNH, Smithsonian Institution");
expected.put(DcElement.creator.simpleName().toLowerCase(), "Conveyor Belt");
expected.put(AcTerm.providerLiteral.simpleName().toLowerCase(), "Smithsonian Institution, NMNH, Botany");
expected.put("`format`", "image/jpeg");
@djtfmartin
djtfmartin force-pushed the fix/526-ext-duplicate-keys branch from eefc8fe to 9689acb Compare June 23, 2026 12:40
@djtfmartin
djtfmartin merged commit 0d520ae into dev Jun 23, 2026
2 checks passed
@djtfmartin
djtfmartin deleted the fix/526-ext-duplicate-keys branch June 23, 2026 14:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment on lines 279 to 282
} catch (Exception e) {
getSender().tell(e, getSelf()); // inform our master
throw Throwables.propagate(e);
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}
Comment on lines +76 to +77
assertEquals(expected, result);
system.terminate();
expected.put(AcTerm.licenseLogoURL.simpleName().toLowerCase(), "https://www.si.edu/sites/default/files/icons/cc0.svg");
expected.put("dc_rights", "CC0"); // this one wins
expected.put(DcTerm.description.simpleName().toLowerCase(), "Barcode 03538523");
expected.put("dcterms_rights", "CC0"); // this one win
Comment on lines +193 to +215
Map<String, Integer> duplicatesMap = new HashMap<>();
row.forEach((key, value) -> {
if (duplicatesMap.containsKey(key.simpleName().toLowerCase())) {
duplicatesMap.computeIfPresent(key.simpleName().toLowerCase(), (s, i) -> ++i);
} else {
duplicatesMap.put(key.simpleName().toLowerCase(), 1);
}
});

// fix for https://github.com/gbif/occurrence/issues/526
// handle duplicate keys (which are duplicates when the base url is stripped for the CSV)
// Build the normalized map by iterating so we can log duplicates when they occur.
Map<String, String> normalized = new LinkedHashMap<>();
for (Map.Entry<Term, String> e : row.entrySet()) {
Term term = e.getKey();
String fName = term.simpleName();
if (duplicatesMap.get(fName) != null && duplicatesMap.get(fName) > 1) {
fName = term.prefixedName();
}
String normalizeFieldName = TermNormalizationUtils.normalizeFieldName(fName);
normalized.put(normalizeFieldName, e.getValue());
}
extensionData.putAll(normalized);
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.

3 participants