• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kit-data-manager / ro-crate-java / #576

10 Nov 2025 11:54AM UTC coverage: 91.45% (+0.6%) from 90.804%
#576

Pull #279

github

Pfeil
fix: error in local file path detection
Pull Request #279: Next Version (2.1.0-rc4)

238 of 253 new or added lines in 8 files covered. (94.07%)

1 existing line in 1 file now uncovered.

2246 of 2456 relevant lines covered (91.45%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.96
/src/main/java/edu/kit/datamanager/ro_crate/RoCrate.java
1
package edu.kit.datamanager.ro_crate;
2

3
import com.fasterxml.jackson.core.TreeNode;
4
import com.fasterxml.jackson.databind.JsonNode;
5
import com.fasterxml.jackson.databind.ObjectMapper;
6
import com.fasterxml.jackson.databind.node.ObjectNode;
7
import edu.kit.datamanager.ro_crate.context.CrateMetadataContext;
8
import edu.kit.datamanager.ro_crate.context.RoCrateMetadataContext;
9
import edu.kit.datamanager.ro_crate.hierarchy.HierarchyRecognition;
10
import edu.kit.datamanager.ro_crate.hierarchy.HierarchyRecognitionConfig;
11
import edu.kit.datamanager.ro_crate.hierarchy.HierarchyRecognitionResult;
12
import edu.kit.datamanager.ro_crate.entities.AbstractEntity;
13
import edu.kit.datamanager.ro_crate.entities.contextual.ContextualEntity;
14
import edu.kit.datamanager.ro_crate.entities.contextual.JsonDescriptor;
15
import edu.kit.datamanager.ro_crate.entities.data.DataEntity;
16
import edu.kit.datamanager.ro_crate.entities.data.DataSetEntity;
17
import edu.kit.datamanager.ro_crate.entities.data.RootDataEntity;
18
import edu.kit.datamanager.ro_crate.externalproviders.dataentities.ImportFromDataCite;
19
import edu.kit.datamanager.ro_crate.objectmapper.MyObjectMapper;
20
import edu.kit.datamanager.ro_crate.payload.CratePayload;
21
import edu.kit.datamanager.ro_crate.payload.RoCratePayload;
22
import edu.kit.datamanager.ro_crate.preview.CratePreview;
23
import edu.kit.datamanager.ro_crate.preview.CustomPreview;
24
import edu.kit.datamanager.ro_crate.special.CrateVersion;
25
import edu.kit.datamanager.ro_crate.special.JsonUtilFunctions;
26
import edu.kit.datamanager.ro_crate.validation.JsonSchemaValidation;
27
import edu.kit.datamanager.ro_crate.validation.Validator;
28
import java.io.File;
29
import java.net.URI;
30
import java.util.*;
31
import java.util.stream.Collectors;
32
import java.util.stream.StreamSupport;
33

34
/**
35
 * The class that represents a single ROCrate.
36
 * <p>
37
 * To build or modify it, use a instance of {@link RoCrateBuilder}. In the case
38
 * features of RO-Crate DRAFT specifications are needed, refer to
39
 * {@link BuilderWithDraftFeatures} and its documentation.
40
 *
41
 * @author Nikola Tzotchev on 6.2.2022 г.
42
 * @version 1
43
 */
44
public class RoCrate implements Crate {
45

46
    protected final CratePayload roCratePayload;
47
    protected CrateMetadataContext metadataContext;
48
    protected CratePreview roCratePreview;
49
    protected RootDataEntity rootDataEntity;
50
    protected ContextualEntity jsonDescriptor;
51

52
    protected Collection<File> untrackedFiles;
53

54
    /**
55
     * Indicates whether this crate has been imported from an external source.
56
     * This is used to determine if ro-crate-java should add a CreateAction
57
     * or an UpdateAction in the provenance on export.
58
     */
59
    protected boolean isImported = false;
1✔
60

61
    @Override
62
    public RoCrate markAsImported() {
63
        this.isImported = true;
1✔
64
        return this;
1✔
65
    }
66

67
    @Override
68
    public boolean isImported() {
69
        return this.isImported;
1✔
70
    }
71

72
    @Override
73
    public CratePreview getPreview() {
74
        return this.roCratePreview;
1✔
75
    }
76

77
    public void setRoCratePreview(CratePreview preview) {
78
        this.roCratePreview = preview;
1✔
79
    }
1✔
80

81
    @Override
82
    public void setMetadataContext(CrateMetadataContext metadataContext) {
83
        this.metadataContext = metadataContext;
1✔
84
    }
1✔
85

86
    @Override
87
    public String getMetadataContextValueOf(String key) {
88
        return this.metadataContext.getValueOf(key);
1✔
89
    }
90

91
    @Override
92
    public Set<String> getMetadataContextKeys() {
93
        return this.metadataContext.getKeys();
1✔
94
    }
95

96
    @Override
97
    public Map<String, String> getMetadataContextPairs() {
98
        return this.metadataContext.getPairs();
1✔
99
    }
100

101
    public ContextualEntity getJsonDescriptor() {
102
        return jsonDescriptor;
1✔
103
    }
104

105
    @Override
106
    public void setJsonDescriptor(ContextualEntity jsonDescriptor) {
107
        this.jsonDescriptor = jsonDescriptor;
1✔
108
    }
1✔
109

110
    @Override
111
    public RootDataEntity getRootDataEntity() {
112
        return rootDataEntity;
1✔
113
    }
114

115
    @Override
116
    public void setRootDataEntity(RootDataEntity rootDataEntity) {
117
        this.rootDataEntity = rootDataEntity;
1✔
118
    }
1✔
119

120
    /**
121
     * Default constructor for creation of an empty crate.
122
     */
123
    public RoCrate() {
1✔
124
        this.roCratePayload = new RoCratePayload();
1✔
125
        this.untrackedFiles = new HashSet<>();
1✔
126
        this.metadataContext = new RoCrateMetadataContext();
1✔
127
        rootDataEntity = new RootDataEntity.RootDataEntityBuilder().build();
1✔
128
        jsonDescriptor = new JsonDescriptor();
1✔
129
    }
1✔
130

131
    /**
132
     * A constructor for creating the crate using a Crate builder for easier
133
     * creation.
134
     *
135
     * @param roCrateBuilder the builder to use.
136
     */
137
    public RoCrate(RoCrateBuilder roCrateBuilder) {
1✔
138
        this.roCratePayload = roCrateBuilder.payload;
1✔
139
        this.metadataContext = roCrateBuilder.metadataContext;
1✔
140
        this.roCratePreview = roCrateBuilder.preview;
1✔
141
        this.rootDataEntity = roCrateBuilder.rootDataEntity;
1✔
142
        this.jsonDescriptor = roCrateBuilder.descriptorBuilder.build();
1✔
143
        this.untrackedFiles = roCrateBuilder.untrackedFiles;
1✔
144
        Validator defaultValidation = new Validator(new JsonSchemaValidation());
1✔
145
        defaultValidation.validate(this);
1✔
146
    }
1✔
147

148
    @Override
149
    public Optional<CrateVersion> getVersion() {
150
        JsonNode conformsTo = this.jsonDescriptor.getProperty("conformsTo");
1✔
151
        if (conformsTo.isArray()) {
1✔
152
            return StreamSupport.stream(conformsTo.spliterator(), false)
1✔
153
                .filter(TreeNode::isObject)
1✔
154
                .map(obj -> obj.path("@id").asText())
1✔
155
                .map(CrateVersion::fromSpecUri)
1✔
156
                .filter(Optional::isPresent)
1✔
157
                .map(Optional::get)
1✔
158
                .findFirst();
1✔
159
        } else if (conformsTo.isObject()) {
1✔
160
            return CrateVersion.fromSpecUri(conformsTo.get("@id").asText());
1✔
161
        } else {
162
            return Optional.empty();
×
163
        }
164
    }
165

166
    @Override
167
    public Collection<String> getProfiles() {
168
        JsonNode conformsTo = this.jsonDescriptor.getProperty("conformsTo");
1✔
169
        if (conformsTo.isArray()) {
1✔
170
            return StreamSupport.stream(conformsTo.spliterator(), false)
1✔
171
                .filter(TreeNode::isObject)
1✔
172
                .map(obj -> obj.path("@id").asText())
1✔
173
                .collect(Collectors.toSet());
1✔
174
        } else {
175
            return Collections.emptySet();
1✔
176
        }
177
    }
178

179
    @Override
180
    public String getJsonMetadata() {
181
        ObjectMapper objectMapper = MyObjectMapper.getMapper();
1✔
182
        ObjectNode node = objectMapper.createObjectNode();
1✔
183

184
        node.setAll(this.metadataContext.getContextJsonEntity());
1✔
185

186
        var graph = objectMapper.createArrayNode();
1✔
187
        ObjectNode root = objectMapper.convertValue(
1✔
188
            this.rootDataEntity,
189
            ObjectNode.class
190
        );
191
        graph.add(root);
1✔
192

193
        graph.add(
1✔
194
            objectMapper.convertValue(this.jsonDescriptor, JsonNode.class)
1✔
195
        );
196
        if (
1✔
197
            this.roCratePayload != null &&
198
            this.roCratePayload.getEntitiesMetadata() != null
1✔
199
        ) {
200
            graph.addAll(this.roCratePayload.getEntitiesMetadata());
1✔
201
        }
202
        node.set("@graph", graph);
1✔
203
        return node.toString();
1✔
204
    }
205

206
    @Override
207
    public DataEntity getDataEntityById(String id) {
208
        return this.roCratePayload.getDataEntityById(id);
1✔
209
    }
210

211
    @Override
212
    public Optional<DataSetEntity> getDataSetById(String id) {
213
        DataEntity data = this.roCratePayload.getDataEntityById(id);
1✔
214
        if (data instanceof DataSetEntity) {
1✔
215
            return Optional.of((DataSetEntity) data);
1✔
216
        }
NEW
217
        return Optional.empty();
×
218
    }
219

220
    @Override
221
    public Set<DataEntity> getAllDataEntities() {
222
        return new HashSet<>(this.roCratePayload.getAllDataEntities());
1✔
223
    }
224

225
    @Override
226
    public ContextualEntity getContextualEntityById(String id) {
227
        return this.roCratePayload.getContextualEntityById(id);
1✔
228
    }
229

230
    @Override
231
    public Set<ContextualEntity> getAllContextualEntities() {
232
        return new HashSet<>(this.roCratePayload.getAllContextualEntities());
1✔
233
    }
234

235
    @Override
236
    public AbstractEntity getEntityById(String id) {
237
        return this.roCratePayload.getEntityById(id);
1✔
238
    }
239

240
    /**
241
     * {@inheritDoc}
242
     * <p>
243
     * Note: This will also link the DataEntity to the root node using the root
244
     * nodes hasPart property.
245
     *
246
     * @param entity the DataEntity to add to this crate.
247
     */
248
    @Override
249
    public void addDataEntity(DataEntity entity) {
250
        this.metadataContext.checkEntity(entity);
1✔
251
        this.roCratePayload.addDataEntity(entity);
1✔
252
        this.rootDataEntity.addToHasPart(entity.getId());
1✔
253
    }
1✔
254

255
    @Override
256
    public void addDataEntity(DataEntity entity, String parentId)
257
        throws IllegalArgumentException {
258
        if (parentId == null) {
1✔
NEW
259
            throw new IllegalArgumentException("Parent ID is null.");
×
260
        }
261

262
        DataEntity parentEntity = parentId.equals("./")
1✔
263
                ? this.getRootDataEntity()
1✔
264
                : this.getDataEntityById(parentId);
1✔
265

266
        if (parentEntity == null) {
1✔
267
            throw new IllegalArgumentException(
1✔
268
                "Parent ID not found in the crate."
269
            );
270
        }
271

272
        if (parentEntity.getTypes().contains("File")) {
1✔
NEW
273
            throw new IllegalArgumentException(
×
274
                "Parent entity cannot be a File."
275
            );
276
        }
277

278
        if (!parentEntity.getTypes().contains("Dataset")) {
1✔
NEW
279
            throw new IllegalArgumentException(
×
280
                "Parent entity must be a Dataset in order to contain another DataEntity as a part."
281
            );
282
        }
283

284
        this.metadataContext.checkEntity(entity);
1✔
285

286
        if (parentEntity instanceof DataSetEntity) {
1✔
287
            ((DataSetEntity) parentEntity).addToHasPart(entity.getId());
1✔
288
        } else {
NEW
289
            parentEntity.addProperty("hasPart", entity.getId());
×
290
        }
291
        this.roCratePayload.addDataEntity(entity);
1✔
292
    }
1✔
293

294
    @Override
295
    public void addContextualEntity(ContextualEntity entity) {
296
        this.metadataContext.checkEntity(entity);
1✔
297
        this.roCratePayload.addContextualEntity(entity);
1✔
298
    }
1✔
299

300
    @Override
301
    public void deleteEntityById(String entityId) {
302
        // delete the entity firstly
303
        this.roCratePayload.removeEntityById(entityId);
1✔
304
        // remove from the root data entity hasPart
305
        this.rootDataEntity.removeFromHasPart(entityId);
1✔
306
        // remove from the root entity and the file descriptor
307
        JsonUtilFunctions.removeFieldsWith(
1✔
308
            entityId,
309
            this.rootDataEntity.getProperties()
1✔
310
        );
311
        JsonUtilFunctions.removeFieldsWith(
1✔
312
            entityId,
313
            this.jsonDescriptor.getProperties()
1✔
314
        );
315
    }
1✔
316

317
    @Override
318
    public void setUntrackedFiles(Collection<File> files) {
319
        this.untrackedFiles = files;
1✔
320
    }
1✔
321

322
    @Override
323
    public void deleteValuePairFromContext(String key) {
324
        this.metadataContext.deleteValuePairFromContext(key);
1✔
325
    }
1✔
326

327
    @Override
328
    public void deleteUrlFromContext(String key) {
329
        this.metadataContext.deleteUrlFromContext(key);
1✔
330
    }
1✔
331

332
    @Override
333
    public void addFromCollection(
334
        Collection<? extends AbstractEntity> entities
335
    ) {
336
        this.roCratePayload.addEntities(entities);
1✔
337
    }
1✔
338

339
    @Override
340
    public void addItemFromDataCite(String locationUrl) {
341
        ImportFromDataCite.addDataCiteToCrate(locationUrl, this);
×
342
    }
×
343

344
    @Override
345
    public Collection<File> getUntrackedFiles() {
346
        return this.untrackedFiles;
1✔
347
    }
348

349
    @Override
350
    public HierarchyRecognitionResult createDataEntityFileStructure(
351
        boolean addInverseRelationships
352
    ) {
353
        HierarchyRecognitionConfig config = new HierarchyRecognitionConfig()
1✔
354
                .withSetInverseRelationships(addInverseRelationships);
1✔
355
        return this.createDataEntityFileStructure(config);
1✔
356
    }
357

358
    @Override
359
    public HierarchyRecognitionResult createDataEntityFileStructure(
360
        HierarchyRecognitionConfig config
361
    ) {
362
        return new HierarchyRecognition(this, config).buildHierarchy();
1✔
363
    }
364

365
    /**
366
     * The inner class builder for the easier creation of a ROCrate.
367
     */
368
    public static class RoCrateBuilder {
369

370
        private static final String PROPERTY_DESCRIPTION = "description";
371

372
        CratePayload payload;
373
        CratePreview preview = new CustomPreview();
1✔
374
        CrateMetadataContext metadataContext;
375
        ContextualEntity license;
376
        RootDataEntity rootDataEntity;
377
        Collection<File> untrackedFiles = new HashSet<>();
1✔
378

379
        JsonDescriptor.Builder descriptorBuilder = new JsonDescriptor.Builder();
1✔
380

381
        /**
382
         * The default constructor of a builder.
383
         *
384
         * @param name the name of the crate.
385
         * @param description the description of the crate.
386
         * @param datePublished the published date of the crate.
387
         * @param licenseId the license identifier of the crate.
388
         */
389
        public RoCrateBuilder(
390
            String name,
391
            String description,
392
            String datePublished,
393
            String licenseId
394
        ) {
1✔
395
            this.payload = new RoCratePayload();
1✔
396
            this.metadataContext = new RoCrateMetadataContext();
1✔
397
            this.rootDataEntity = new RootDataEntity.RootDataEntityBuilder()
1✔
398
                .addProperty("name", name)
1✔
399
                .addProperty(PROPERTY_DESCRIPTION, description)
1✔
400
                .build();
1✔
401
            this.setLicense(licenseId);
1✔
402
            this.addDatePublishedWithExceptions(datePublished);
1✔
403
        }
1✔
404

405
        /**
406
         * The default constructor of a builder.
407
         *
408
         * @param name the name of the crate.
409
         * @param description the description of the crate.
410
         * @param datePublished the published date of the crate.
411
         * @param license the license entity of the crate.
412
         */
413
        public RoCrateBuilder(
414
            String name,
415
            String description,
416
            String datePublished,
417
            ContextualEntity license
418
        ) {
1✔
419
            this.payload = new RoCratePayload();
1✔
420
            this.metadataContext = new RoCrateMetadataContext();
1✔
421
            this.rootDataEntity = new RootDataEntity.RootDataEntityBuilder()
1✔
422
                .addProperty("name", name)
1✔
423
                .addProperty(PROPERTY_DESCRIPTION, description)
1✔
424
                .build();
1✔
425
            this.setLicense(license);
1✔
426
            this.addDatePublishedWithExceptions(datePublished);
1✔
427
        }
1✔
428

429
        /**
430
         * A default constructor without any params where the root data entity
431
         * will be plain.
432
         */
433
        public RoCrateBuilder() {
1✔
434
            this.payload = new RoCratePayload();
1✔
435
            this.metadataContext = new RoCrateMetadataContext();
1✔
436
            rootDataEntity = new RootDataEntity.RootDataEntityBuilder().build();
1✔
437
        }
1✔
438

439
        /**
440
         * A constructor with a crate as template.
441
         *
442
         * @param crate the crate to copy.
443
         */
444
        public RoCrateBuilder(RoCrate crate) {
1✔
445
            this.payload = crate.roCratePayload;
1✔
446
            this.preview = crate.roCratePreview;
1✔
447
            this.metadataContext = crate.metadataContext;
1✔
448
            this.rootDataEntity = crate.rootDataEntity;
1✔
449
            this.untrackedFiles = crate.untrackedFiles;
1✔
450
            this.descriptorBuilder = new JsonDescriptor.Builder(crate);
1✔
451
        }
1✔
452

453
        public RoCrateBuilder addName(String name) {
454
            this.rootDataEntity.addProperty("name", name);
1✔
455
            return this;
1✔
456
        }
457

458
        /**
459
         * Adds an "identifier" property to the root data entity.
460
         * <p>
461
         * This is useful e.g. to assign e.g. a DOI to this crate.
462
         * @param identifier the identifier to add.
463
         * @return this builder.
464
         */
465
        public RoCrateBuilder addIdentifier(String identifier) {
466
            this.rootDataEntity.addProperty("identifier", identifier.strip());
1✔
467
            return this;
1✔
468
        }
469

470
        public RoCrateBuilder addDescription(String description) {
471
            this.rootDataEntity.addProperty(PROPERTY_DESCRIPTION, description);
1✔
472
            return this;
1✔
473
        }
474

475
        /**
476
         * Adds a data entity to the crate.
477
         * <p>
478
         * Note: This will also link the DataEntity to the root node using the
479
         * root nodes hasPart property.
480
         *
481
         * @param dataEntity the DataEntity to add to this crate.
482
         * @return returns the builder for further usage.
483
         */
484
        public RoCrateBuilder addDataEntity(DataEntity dataEntity) {
485
            this.metadataContext.checkEntity(dataEntity);
1✔
486
            this.payload.addDataEntity(dataEntity);
1✔
487
            this.rootDataEntity.addToHasPart(dataEntity.getId());
1✔
488
            return this;
1✔
489
        }
490

491
        public void addDataEntity(DataEntity entity, String parentId)
492
            throws IllegalArgumentException {
493
            if (parentId == null) {
1✔
NEW
494
                throw new IllegalArgumentException("Parent ID is null.");
×
495
            }
496

497
            DataEntity parentEntity = parentId.equals("./")
1✔
498
                    ? this.rootDataEntity
1✔
499
                    : this.payload.getDataEntityById(parentId);
1✔
500

501
            if (parentEntity == null) {
1✔
502
                throw new IllegalArgumentException(
1✔
503
                    "Parent ID not found in the crate."
504
                );
505
            }
506

507
            if (parentEntity.getTypes().contains("File")) {
1✔
NEW
508
                throw new IllegalArgumentException(
×
509
                    "Parent entity cannot be a File."
510
                );
511
            }
512

513
            if (!parentEntity.getTypes().contains("Dataset")) {
1✔
NEW
514
                throw new IllegalArgumentException(
×
515
                    "Parent entity must be a Dataset in order to contain another DataEntity as a part."
516
                );
517
            }
518

519
            this.metadataContext.checkEntity(entity);
1✔
520

521
            if (parentEntity instanceof DataSetEntity) {
1✔
522
                ((DataSetEntity) parentEntity).addToHasPart(entity.getId());
1✔
523
            } else {
NEW
524
                parentEntity.addProperty("hasPart", entity.getId());
×
525
            }
526
            this.payload.addDataEntity(entity);
1✔
527
        }
1✔
528

529
        public RoCrateBuilder addContextualEntity(
530
            ContextualEntity contextualEntity
531
        ) {
532
            this.metadataContext.checkEntity(contextualEntity);
1✔
533
            this.payload.addContextualEntity(contextualEntity);
1✔
534
            return this;
1✔
535
        }
536

537
        /**
538
         * Setting the license of the crate.
539
         *
540
         * @param license the license to set.
541
         * @return this builder.
542
         */
543
        public RoCrateBuilder setLicense(ContextualEntity license) {
544
            this.license = license;
1✔
545
            // From our tests, it seems like if we only have the ID for our license, we do
546
            // not need to add an extra entity.
547
            if (license.getProperties().size() > 1) {
1✔
548
                this.addContextualEntity(license);
1✔
549
            }
550
            this.rootDataEntity.addIdProperty("license", license.getId());
1✔
551
            return this;
1✔
552
        }
553

554
        /**
555
         * Setting the license of the crate using only a license identifier.
556
         *
557
         * @param licenseId the licenses identifier. Should be a resolveable
558
         * URI.
559
         * @return the builder
560
         */
561
        public RoCrateBuilder setLicense(String licenseId) {
562
            ContextualEntity licenseEntity =
1✔
563
                new ContextualEntity.ContextualEntityBuilder()
564
                    .setId(licenseId)
1✔
565
                    .build();
1✔
566
            this.setLicense(licenseEntity);
1✔
567
            return this;
1✔
568
        }
569

570
        /**
571
         * Adds a property with date time format. The property should match the
572
         * ISO 8601 date format.
573
         *
574
         * @param dateValue time string in ISO 8601 format
575
         * @return this builder
576
         * @throws IllegalArgumentException if format is not ISO 8601
577
         */
578
        public RoCrateBuilder addDatePublishedWithExceptions(String dateValue)
579
            throws IllegalArgumentException {
580
            this.rootDataEntity.addDateTimePropertyWithExceptions(
1✔
581
                "datePublished",
582
                dateValue
583
            );
584
            return this;
1✔
585
        }
586

587
        public RoCrateBuilder setContext(CrateMetadataContext context) {
588
            this.metadataContext = context;
×
589
            return this;
×
590
        }
591

592
        public RoCrateBuilder addUrlToContext(String url) {
593
            this.metadataContext.addToContextFromUrl(url);
1✔
594
            return this;
1✔
595
        }
596

597
        public RoCrateBuilder addValuePairToContext(String key, String value) {
598
            this.metadataContext.addToContext(key, value);
1✔
599
            return this;
1✔
600
        }
601

602
        public RoCrateBuilder setPreview(CratePreview preview) {
603
            this.preview = preview;
1✔
604
            return this;
1✔
605
        }
606

607
        public RoCrateBuilder addUntrackedFile(File file) {
608
            this.untrackedFiles.add(file);
1✔
609
            return this;
1✔
610
        }
611

612
        /**
613
         * @return a crate with the information from this builder.
614
         */
615
        public RoCrate build() {
616
            return new RoCrate(this);
1✔
617
        }
618
    }
619

620
    /**
621
     * Builder for Crates, supporting features which are not in a final
622
     * specification yet.
623
     * <p>
624
     * NOTE: This will change the specification version of your crate.
625
     * <p>
626
     * We only add features we expect to be in the new specification in the end.
627
     * In case a feature will not make it into the specification, we will mark
628
     * it as deprecated and remove it in new major versions. If a feature is
629
     * finalized, it will be added to the stable {@link RoCrateBuilder} and
630
     * marked as deprecated in this class.
631
     */
632
    public static class BuilderWithDraftFeatures extends RoCrateBuilder {
633

634
        /**
635
         * @see RoCrateBuilder#RoCrateBuilder()
636
         */
637
        public BuilderWithDraftFeatures() {
638
            super();
1✔
639
        }
1✔
640

641
        /**
642
         * @see RoCrateBuilder#RoCrateBuilder(String, String, String, String)
643
         */
644
        public BuilderWithDraftFeatures(
645
            String name,
646
            String description,
647
            String datePublished,
648
            String licenseId
649
        ) {
650
            super(name, description, datePublished, licenseId);
×
651
        }
×
652

653
        /**
654
         * @see RoCrateBuilder#RoCrateBuilder(String, String, String,
655
         * ContextualEntity)
656
         */
657
        public BuilderWithDraftFeatures(
658
            String name,
659
            String description,
660
            String datePublished,
661
            ContextualEntity licenseId
662
        ) {
663
            super(name, description, datePublished, licenseId);
×
664
        }
×
665

666
        /**
667
         * @see RoCrateBuilder#RoCrateBuilder(RoCrate)
668
         */
669
        public BuilderWithDraftFeatures(RoCrate crate) {
670
            super(crate);
1✔
671
            this.descriptorBuilder = new JsonDescriptor.Builder(crate);
1✔
672
        }
1✔
673

674
        /**
675
         * Indicate this crate also conforms to the given specification, in
676
         * addition to the version this builder adds.
677
         * <p>
678
         * This is helpful for profiles or other specifications the crate
679
         * conforms to. Can be called multiple times to add more specifications.
680
         *
681
         * @param specification a specification or profile this crate conforms
682
         * to.
683
         * @return the builder
684
         */
685
        public BuilderWithDraftFeatures alsoConformsTo(URI specification) {
686
            descriptorBuilder
1✔
687
                .addConformsTo(specification)
1✔
688
                // usage of a draft feature results in draft version numbers of the crate
689
                .setVersion(CrateVersion.LATEST_UNSTABLE);
1✔
690
            return this;
1✔
691
        }
692
    }
693
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc