Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
02fe2c8
docs: convert minimal example from README to a test
Pfeil May 2, 2025
d43edf7
fix: avoid adding the same id property multiple times
Pfeil May 2, 2025
ac06985
cleanup: clean up unused imports and improve code formatting
Pfeil May 2, 2025
e9a3bd5
ci: always run CI on pull requests
Pfeil May 2, 2025
b167bae
Merge pull request #257 from kit-data-manager/fix-adding-id-property-…
Pfeil May 2, 2025
d47f90d
refactor(tests): factor out helper methods
Pfeil May 2, 2025
0c43211
docs: update examples in ExamplesOfSpecificationV1p1Test with reposit…
Pfeil May 2, 2025
424b8f6
chore: improve readability of test to make it more of a guide
Pfeil May 2, 2025
375e53a
docs: add javadocs to RoCrateBuilder.addIdentifier
Pfeil May 2, 2025
27d671e
docs: convert files-and-folders example from README to a test
Pfeil May 2, 2025
f24a7a6
docs: enhance Javadoc for id property in AbstractEntity to clarify ID…
Pfeil May 2, 2025
917b89f
fix: javadoc compilation with java 17 does not support @apiNote
Pfeil May 2, 2025
b551a8c
docs: enhance Javadoc in ExamplesOfSpecificationV1p1Test to introduce…
Pfeil May 2, 2025
d35c176
docs: convert web-based-data-entities example from README to a test
Pfeil May 2, 2025
fe02a9f
docs: fix example description for web-based data entities in Examples…
Pfeil May 2, 2025
8ab6f1b
docs: convert file-author-location example from README to a test
Pfeil May 2, 2025
8197ce8
fix: file-author-location test is missing license and datePublished.
Pfeil May 2, 2025
a8e8e2e
docs: add complete workflow example test
Pfeil May 2, 2025
3eec23d
docs: refactor specification examples section in README into other ex…
Pfeil May 2, 2025
61fd863
docs: move quickstart to LearnByExampleTest so it is always tested pr…
Pfeil May 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ on:
push:
branches: [ main, development ]
pull_request:
branches: [ main, development ]
workflow_dispatch:

env:
Expand Down
691 changes: 19 additions & 672 deletions README.md

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions src/main/java/edu/kit/datamanager/ro_crate/RoCrate.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@
import edu.kit.datamanager.ro_crate.entities.AbstractEntity;
import edu.kit.datamanager.ro_crate.entities.contextual.ContextualEntity;
import edu.kit.datamanager.ro_crate.entities.contextual.JsonDescriptor;
import edu.kit.datamanager.ro_crate.entities.contextual.OrganizationEntity;
import edu.kit.datamanager.ro_crate.entities.data.DataEntity;
import edu.kit.datamanager.ro_crate.entities.data.DataEntity.DataEntityBuilder;
import edu.kit.datamanager.ro_crate.entities.data.FileEntity;

import edu.kit.datamanager.ro_crate.entities.data.RootDataEntity;
import edu.kit.datamanager.ro_crate.externalproviders.dataentities.ImportFromDataCite;
import edu.kit.datamanager.ro_crate.externalproviders.organizationprovider.RorProvider;
import edu.kit.datamanager.ro_crate.objectmapper.MyObjectMapper;
import edu.kit.datamanager.ro_crate.payload.CratePayload;
import edu.kit.datamanager.ro_crate.payload.RoCratePayload;
Expand All @@ -26,12 +23,9 @@
import edu.kit.datamanager.ro_crate.special.JsonUtilFunctions;
import edu.kit.datamanager.ro_crate.validation.JsonSchemaValidation;
import edu.kit.datamanager.ro_crate.validation.Validator;
import edu.kit.datamanager.ro_crate.writer.FolderWriter;
import edu.kit.datamanager.ro_crate.writer.RoCrateWriter;

import java.io.File;
import java.net.URI;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -354,6 +348,18 @@ public RoCrateBuilder addName(String name) {
return this;
}

/**
* Adds an "identifier" property to the root data entity.
* <p>
* This is useful e.g. to assign e.g. a DOI to this crate.
* @param identifier the identifier to add.
* @return this builder.
*/
public RoCrateBuilder addIdentifier(String identifier) {
this.rootDataEntity.addProperty("identifier", identifier.strip());
return this;
}

public RoCrateBuilder addDescription(String description) {
this.rootDataEntity.addProperty(PROPERTY_DESCRIPTION, description);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,33 +239,60 @@ private static boolean addProperty(ObjectNode whereToAdd, String key, JsonNode v
* @param id the "id" of the property.
*/
public void addIdProperty(String name, String id) {
JsonNode jsonNode = addToIdProperty(name, id, this.properties.get(name));
if (jsonNode != null) {
this.linkedTo.add(id);
this.properties.set(name, jsonNode);
this.notifyObservers();
}
mergeIdIntoValue(id, this.properties.get(name))
.ifPresent(newValue -> {
this.linkedTo.add(id);
this.properties.set(name, newValue);
this.notifyObservers();
});
}

private static JsonNode addToIdProperty(String name, String id, JsonNode property) {
ObjectMapper objectMapper = MyObjectMapper.getMapper();
if (name != null && id != null) {
if (property == null) {
return objectMapper.createObjectNode().put("@id", id);
} else {
if (property.isArray()) {
ArrayNode ns = (ArrayNode) property;
ns.add(objectMapper.createObjectNode().put("@id", id));
return ns;
} else {
ArrayNode newNodes = objectMapper.createArrayNode();
newNodes.add(property);
newNodes.add(objectMapper.createObjectNode().put("@id", id));
return newNodes;
}
}
/**
* Merges the given id into the current value,
* using this representation: {"@id" : "id"}.
* <p>
* The current value can be null without errors.
* Only the id will be considered in this case.
* <p>
* If the id is null-ish, it will not be added, similar to a null-ish value.
* If the id is already present, nothing will be done.
* If it is not an array and the id is not present, an array will be applied.
*
* @param id the id to add.
* @param currentValue the current value of the property.
* @return The updated value of the property.
* Empty if value does not change!
*/
private static Optional<JsonNode> mergeIdIntoValue(String id, JsonNode currentValue) {
if (id == null || id.isBlank()) { return Optional.empty(); }

ObjectMapper jsonBuilder = MyObjectMapper.getMapper();
ObjectNode newIdObject = jsonBuilder.createObjectNode().put("@id", id);
if (currentValue == null || currentValue.isNull() || currentValue.isMissingNode()) {
return Optional.ofNullable(newIdObject);
}

boolean isIdAlready = currentValue.asText().equals(id);
boolean isIdObjectAlready = currentValue.path("@id").asText().equals(id);
boolean isArrayWithIdPresent = currentValue.valueStream()
.anyMatch(node -> node
.path("@id")
.asText()
.equals(id));
if (isIdAlready || isIdObjectAlready || isArrayWithIdPresent) {
return Optional.empty();
}

if (currentValue.isArray() && currentValue instanceof ArrayNode currentValueAsArray) {
currentValueAsArray.add(newIdObject);
return Optional.of(currentValueAsArray);
} else {
// property is not an array, so we make it an array
ArrayNode newNodes = jsonBuilder.createArrayNode();
newNodes.add(currentValue);
newNodes.add(newIdObject);
return Optional.of(newNodes);
}
return null;
}

/**
Expand Down Expand Up @@ -369,6 +396,11 @@ protected String getId() {
/**
* Setting the id property of the entity, if the given value is not
* null. If the id is not encoded, the encoding will be done.
* <p>
* <b>NOTE: IDs are not just names!</b> The ID may have effects
* on parts of your crate! For example: If the entity represents a
* file which will be copied into the crate, writers must use the
* ID as filename.
*
* @param id the String representing the id.
* @return the generic builder.
Expand Down Expand Up @@ -486,11 +518,11 @@ public T addProperty(String key, boolean value) {
* @return the generic builder
*/
public T addIdProperty(String name, String id) {
JsonNode jsonNode = AbstractEntity.addToIdProperty(name, id, this.properties.get(name));
if (jsonNode != null) {
this.properties.set(name, jsonNode);
this.relatedItems.add(id);
}
AbstractEntity.mergeIdIntoValue(id, this.properties.get(name))
.ifPresent(newValue -> {
this.properties.set(name, newValue);
this.relatedItems.add(id);
});
return self();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import edu.kit.datamanager.ro_crate.util.ZipUtil;
import java.io.File;
import java.io.IOException;
import java.util.Optional;

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
Expand All @@ -13,7 +12,7 @@
/**
* This class adds a static preview to the crate, which consists of a
* metadataHtml file and a folder containing other files required to render
* metadataHtml. If will be put unchanged to the writer output, i.e., a zip
* metadataHtml. It will be put unchanged to the writer output, i.e., a zip
* file, folder, or stream.
*
* @author jejkal
Expand Down
39 changes: 37 additions & 2 deletions src/test/java/edu/kit/datamanager/ro_crate/HelpFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.fasterxml.jackson.databind.SerializationFeature;
import edu.kit.datamanager.ro_crate.entities.AbstractEntity;
import edu.kit.datamanager.ro_crate.objectmapper.MyObjectMapper;
import edu.kit.datamanager.ro_crate.special.JsonUtilFunctions;

import org.apache.commons.io.FileUtils;
import io.json.compare.JSONCompare;
import io.json.compare.JsonComparator;
import org.opentest4j.AssertionFailedError;

import java.io.File;
import java.io.IOException;
Expand All @@ -34,15 +36,15 @@ public static void compareEntityWithFile(AbstractEntity entity, String string) t

public static void compare(JsonNode node1, JsonNode node2, Boolean equals) {
var comparator = new JsonComparator() {
public boolean compareValues(Object expected, Object actual) {

public boolean compareValues(Object expected, Object actual) {
return expected.equals(actual);
}

public boolean compareFields(String expected, String actual) {
return expected.equals(actual);
}
};

if (equals) {
JSONCompare.assertMatches(node1, node2, comparator);
} else {
Expand Down Expand Up @@ -73,13 +75,46 @@ public static void compareTwoCrateJson(Crate crate1, Crate crate2) throws JsonPr
compare(node1, node2, true);
}

public static void prettyPrintJsonString(String minimalJsonMetadata) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(minimalJsonMetadata);
// Enable pretty printing
String prettyJson = objectMapper
.enable(SerializationFeature.INDENT_OUTPUT)
.writeValueAsString(jsonNode);
// Print the pretty JSON
System.out.println(prettyJson);
} catch (JsonProcessingException e) {
throw new AssertionFailedError("Not able to process string as JSON!", e);
}
}

public static void printAndAssertEquals(RoCrate crate, String pathToResource) {
// So you get something to see
prettyPrintJsonString(crate.getJsonMetadata());
// Compare with the example from the specification
try {
HelpFunctions.compareCrateJsonToFileInResources(crate, pathToResource);
} catch (IOException e) {
throw new AssertionFailedError("Missing resources file!", e);
}
}

public static void compareCrateJsonToFileInResources(File file1, File file2) throws IOException {
ObjectMapper objectMapper = MyObjectMapper.getMapper();
JsonNode node1 = JsonUtilFunctions.unwrapSingleArray(objectMapper.readTree(file1));
JsonNode node2 = JsonUtilFunctions.unwrapSingleArray(objectMapper.readTree(file2));
compare(node1, node2, true);
}

/**
* Compares the JSON metadata of a Crate object with a JSON file in the resources directory.
*
* @param crate1 The Crate object to compare.
* @param jsonFileString The path to the JSON file in the resources directory.
* @throws IOException If an error occurs while reading the JSON file.
*/
public static void compareCrateJsonToFileInResources(Crate crate1, String jsonFileString) throws IOException {
InputStream inputStream = HelpFunctions.class.getResourceAsStream(
jsonFileString);
Expand Down
Loading