Java library containing Domain Object classes of the Digital Collection's and Digital Humanities ecosystem. Primarily started from the needs for GLAMs (Galleries, Libraries, Archives, Museums) but not restricted to it.
The domain model follows the FRBR (Functional Requirements for Bibliographic Records). The model is not restricted to books but can handle all sort of creative works and their digital counterparts ("digital objects").
One core statement (taken from Music Cataloging at Yale) is:
"A work is realized by an expression, which is embodied in a manifestation, which is exemplified by an item."
And the central object of interest of digital collections is the DigitalObject
as the digital representation of an item
and curated Collections
as group of digital objects.
- For presenting digital collections online the library offers
Website
andWebpage
classes. - For arranging and describing digital objects by topics the library offers
Topic
andSubtopic
classes. - For editorial contribution in the context of digital collections the library offers
Article
with rich text formatting and embedding of different media.
The following classes can be assigned to objects (where appropriate):
- a freely definable
License
- a list of freely definable
Identifier
s, each of them identifying the object uniquely in an external source system, e.g. GND-ID ("gnd:104330171") or VIAF-ID ("viaf:96994450").
The classes are modelled after the business domain model. Common properties and characteristics are expressed through some inheritance (Entity, Identifiable).
This library supports practical handling of above domain model by adding paging, filtering and sorting classes.
Model for passing technology independent filter criterias
- from frontend to backend via URL-params,
- from Java code to backend
Backend has to take care about implementing technology dependent filtering for given criterias.
Example usage in a Spring MVC controller: return only webpages with active publication time range
Example URL: http://localhost/v5/webpages?publicationStart=gte:2021-01-01&publicationEnd=lt:2021-10-01
@Operation(summary = "Get all webpages")
@GetMapping(value = {"/v5/webpages", "/v2/webpages"}, produces = MediaType.APPLICATION_JSON_VALUE)
public PageResponse<Webpage> findAll(
@RequestParam(name = "pageNumber", required = false, defaultValue = "0") int pageNumber,
@RequestParam(name = "pageSize", required = false, defaultValue = "25") int pageSize,
@RequestParam(name = "sortBy", required = false) List<Order> sortBy,
@RequestParam(name = "publicationStart", required = false) FilterCriterion<LocalDate> publicationStart,
@RequestParam(name = "publicationEnd", required = false) FilterCriterion<LocalDate> publicationEnd) {
PageRequest pageRequest = new PageRequest(pageNumber, pageSize);
...
Filtering filtering =
Filtering.defaultBuilder()
.add("publicationStart", publicationStart)
.add("publicationEnd", publicationEnd)
.build();
pageRequest.setFiltering(filtering);
return webpageService.find(pageRequest);
}
REST-API design for filtering was inspired by:
- REST API Design: Filtering, Sorting, and Pagination
- An example application using Spring boot MVC, Spring Data JPA with the ability to do filter, pagination and sorting.
Symbol | Operation | Example filter query param |
---|---|---|
eq | equals | filter=city:eq:Munich |
eq_notset | equals or not set | filter=city:eq_notset:Munich |
neq | not equals | filter=country:neq:de |
gt | greater than | filter=amount:gt:10000 |
gt_notset | greater than or not set | filter=presentationEnd:gt_notset:2020-10-06 |
gte | greater than or equals | filter=amount:gte:10000 |
gte_notset | greater than or equals or not set | filter=amount:gte_notset:10000 |
lt | less than | filter=amount:lt:10000 |
lt_notset | less than or not set | filter=amount:lt_notset:10000 |
lt_set | less than and set | filter=amount:lt_set:10000 |
lte | less than or equals to | filter=amount:lte:10000 |
lte_set | less than or equals and set | filter=presentationStart:lte_set:2020-10-06 |
lte_notset | less than or equals or not set | filter=presentationStart:lte_notset:2020-10-06 |
in | in | filter=country:in:uk,usa,au |
nin | not in | filter=country:nin:fr,de,nz |
btn | between (inclusive) | filter=joiningDate:btn:2018-01-01,2016-01-01 |
like | like | filter=firstName:like:John |
stw | starts with | filter=firstName:stw:A |
set | value exists (not null) | filter=firstName:set: |
notset | value is not set (null) | filter=firstName:notset: |
Comes with a separate module for supporting serializing model objects to JSON (dc-model-jackson module
) using Jackson
Many model objects already provide a builder method, which help to instantiate and fill model objects in a fluent way.
The builder internally holds all attributes of the model class and provides several methods to set or modify them.
By calling the build()
method, the model object is instantiated, filled and returned.
To implement a new builder, it is important to know, how they work internally.
Since Lombok is used, every model class must be annotated
with @SuperBuilder(buildMethodName = "prebuild")
, to enable multi-tier inheritance.
As next step, you have to customize the builder by inheriting it from the upper-tier builder, e.g.:
public abstract static class Tier2Builder<C extends Tier2Object, B extends Tier2Builder<C, B>>
extends Tier1Builder<C, B> {
}
The prebuild
configuration allows manipulation of the auto-generated build
method,
which is renamed to prebuild
, so that you can write your own build
method, which must
at least execute prebuild
.
Since Lombok ignores all member variable pre-settings of the classes (e.g. initializing a list member to an empty Array on instantiation), and internally holds a copy
of all instance variables, an init()
method to initialize the variables where neccessary
was applied, which is executed by the constructor and by the build
method. Please note,
that you can execute init
only after prebuild
, since only prebuild
gives you the
instance of your model object.
As a reference, your build
method, should minimally look like this:
public C build() {
C c = prebuild();
c.init();
return c;
}