Linneo is a Java 21+ library with no runtime dependencies that bundles a data classification taxonomy and applies it
to a data model. A Taxonomy holds three hierarchies of terms keyed with dot notation: data categories (what a
field holds), data uses (why it is processed) and data subjects (whose data it is). The standard taxonomy is
the fideslang default taxonomy plus Linneo’s extensions for non-personal and education data. Every data category
carries the protection it requires (legal nature, confidentiality, integrity, secret), which children inherit and may
only make stricter. Models declare what they hold with annotations, a Classifier checks those annotations in tests,
processing activities tie purposes, data subjects and personal data to their lawful bases and produce the GDPR record
of processing activities, and three exporters translate the taxonomy for a data catalogue: OpenMetadataCatalog
(OpenMetadata classifications and tags), DataHubCatalog (a DataHub business glossary) and AtlasCatalog (Apache
Atlas classifications).
Applications add their own terms through a TaxonomyExtension, and Linneo ships an optional one for universities
that is applied only on request.
This reference describes every public type. For a guided introduction, see the course.
The JAR is the named JPMS module io.github.devbpm.linneo:
module io.github.devbpm.linneo {
exports io.github.devbpm.linneo;
exports io.github.devbpm.linneo.annotation;
exports io.github.devbpm.linneo.classify;
exports io.github.devbpm.linneo.processing;
exports io.github.devbpm.linneo.catalog.openmetadata;
exports io.github.devbpm.linneo.catalog.datahub;
exports io.github.devbpm.linneo.catalog.atlas;
exports io.github.devbpm.linneo.extension.university;
uses io.github.devbpm.linneo.TaxonomyExtension;
}
| Package | Exported | Contents |
|---|---|---|
io.github.devbpm.linneo |
yes | The taxonomy (Taxonomy, TaxonomyBuilder, TaxonomyExtension), its terms (Term, TermInfo, DataCategory, DataUse, DataSubject), the protection enums and the key constants (Categories, DataUses, DataSubjects) |
io.github.devbpm.linneo.annotation |
yes | The annotations that declare what each field of a model holds: @Category, @DefaultCategory, @CategoryByRow, @Exempt |
io.github.devbpm.linneo.classify |
yes | Reading and verifying the annotations of a model: Classifier, ClassClassification, FieldClassification, Violation, ClassificationException |
io.github.devbpm.linneo.processing |
yes | Processing activities and the GDPR record of processing activities: ProcessingActivity, Transfer, LegalBasis, SpecialCategoryCondition, CriminalDataBasis, TransferSafeguard, ProcessingChecker, CheckedActivity, ProcessingViolation, ProcessingException, ProcessingRecord |
io.github.devbpm.linneo.catalog.openmetadata |
yes | The taxonomy as OpenMetadata classifications and tags: OpenMetadataCatalog, OpenMetadataMapping, OmClassification, OmTag. No network calls |
io.github.devbpm.linneo.catalog.datahub |
yes | The taxonomy as a DataHub business glossary: DataHubCatalog, DataHubMapping, DhProposal. No network calls |
io.github.devbpm.linneo.catalog.atlas |
yes | The taxonomy as Apache Atlas classifications: AtlasCatalog, AtlasMapping, AtlasClassificationDef. No network calls |
io.github.devbpm.linneo.extension.university |
yes | An optional extension for universities, not applied by default: UniversityTaxonomy and its key constants UniversityCategories, UniversityDataUses, UniversityDataSubjects |
io.github.devbpm.linneo.internal |
no | StandardTaxonomy, which loads the bundled TSV resources, and Json, the minimal JSON writer shared by the three exporters. Not part of the public API |
The uses clause lets Taxonomy.load() and TaxonomyBuilder.withExtensions() find extensions with
java.util.ServiceLoader; see Extending the taxonomy. The module has no provides clause: the
extensions it ships are applied explicitly; see Extensions.
To use the library from a modular application:
module com.example.app {
requires io.github.devbpm.linneo;
}
Taxonomy model (io.github.devbpm.linneo)
Taxonomy (standard, load, builder, lookups, deprecation, navigation) and
TaxonomyException.Term, TermInfo, DataCategory, DataUse, DataSubject.LegalNature, Confidentiality, Integrity, Identifiability
and the inheritance rule.Categories, DataUses, DataSubjects.TaxonomyBuilder, TaxonomyExtension, CategoryDraft, TermDraft.Extensions (io.github.devbpm.linneo.extension.university)
UniversityTaxonomy, UniversityCategories, UniversityDataUses,
UniversityDataSubjects: every term with its protection, the standard keys to use, routing rules and sources.Annotations (io.github.devbpm.linneo.annotation)
@Category@DefaultCategory@CategoryByRow@ExemptClassification (io.github.devbpm.linneo.classify)
Classifier, ClassificationException.ClassClassification, FieldClassification.Violation and every Code.Processing activities (io.github.devbpm.linneo.processing)
ProcessingActivity, its Builder, Transfer.LegalBasis, SpecialCategoryCondition, CriminalDataBasis,
TransferSafeguard.ProcessingChecker, CheckedActivity, ProcessingViolation and
every Code, ProcessingException.OpenMetadata (io.github.devbpm.linneo.catalog.openmetadata)
OpenMetadataCatalog, OmClassification, OmTag, JSON bodies, tag mapping.OpenMetadataMapping.DataHub (io.github.devbpm.linneo.catalog.datahub)
DataHubCatalog, DhProposal, glossary nodes and terms, ingestProposal bodies,
field terms.DataHubMapping.Apache Atlas (io.github.devbpm.linneo.catalog.atlas)
AtlasCatalog, AtlasClassificationDef, classification types, typedefs and
classification bodies.AtlasMapping.The three exporters publish the same taxonomy and compute the labels of each classified field from the same
FieldClassification; they differ in what the catalogue offers. None of them makes network calls or applies the
labels to your tables: they build request bodies and names.
| OpenMetadata | DataHub | Apache Atlas | |
|---|---|---|---|
| Entry point | OpenMetadataCatalog |
DataHubCatalog |
AtlasCatalog |
| A category becomes | a nested tag DataCategory.<key> in a mutually exclusive classification |
a glossary term urn:li:glossaryTerm:DataCategory.<key>, plus a glossary node if it has children |
a classification type DataCategory.<key> |
| The tree becomes | tag parent |
nodes that mirror the tree, and isRelatedTerms to the parent’s term |
superTypes: a search for a parent finds its sub-classifications |
| Protection implied by a category | not stored in the tag; goes on each column with tagsOf(field) (tagsOf(category) lists it) |
relatedTerms of its term |
not stored in the type; classificationsOf(category) lists it |
| Legal nature | built-in PersonalData.Personal / SpecialCategory (criminal offence data is SpecialCategory) |
PersonalData.Personal / SpecialCategory / CriminalOffence |
PersonalData.Personal / SpecialCategory / CriminalOffence |
| Sensitivity | built-in PII.None / NonSensitive / Sensitive, threshold sensitiveFrom |
— | — |
| Levels and secret | Confidentiality.*, Integrity.*, Identifiability.*, DataHandling.Secret |
the same, as glossary terms | the same, as classifications (not super types of the categories) |
| Created for the standard taxonomy | 5 classifications and 137 tags | 293 proposals: 28 nodes, 140 terms, 125 relation aspects | 146 classification types |
| Requests | PUT /api/v1/classifications, PUT /api/v1/tags, one per body |
POST /aspects?action=ingestProposal, one per proposal |
one POST /api/atlas/v2/types/typedefs |
| Sending again | create or update | UPSERT (replaces each aspect) |
POST answers 409 if the types exist; update with PUT |
| Labels of a field | tagsOf(field): tag names |
termsOf(field): term URNs |
classificationsOf(field): names; classificationsJson(field): request body |
| Applying them (your code) | the table API you already use | for example GraphQL addTerms with the field path as subResource |
POST /api/atlas/v2/entity/guid/{guid}/classifications |
| Names | OpenMetadataMapping: seven names and a threshold |
DataHubMapping: six node names |
AtlasMapping: six root names |