001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *     http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.gbif.api.model.occurrence;
015
016import org.gbif.api.annotation.Experimental;
017import org.gbif.api.model.common.Identifier;
018import org.gbif.api.model.common.LinneanClassification;
019import org.gbif.api.model.common.LinneanClassificationKeys;
020import org.gbif.api.model.common.MediaObject;
021import org.gbif.api.util.ClassificationUtils;
022import org.gbif.api.util.IsoDateInterval;
023import org.gbif.api.vocabulary.BasisOfRecord;
024import org.gbif.api.vocabulary.Continent;
025import org.gbif.api.vocabulary.Country;
026import org.gbif.api.vocabulary.GbifRegion;
027import org.gbif.api.vocabulary.License;
028import org.gbif.api.vocabulary.OccurrenceIssue;
029import org.gbif.api.vocabulary.OccurrenceStatus;
030import org.gbif.api.vocabulary.Rank;
031import org.gbif.api.vocabulary.Sex;
032import org.gbif.api.vocabulary.TaxonomicStatus;
033import org.gbif.dwc.terms.DwcTerm;
034import org.gbif.dwc.terms.GbifTerm;
035import org.gbif.dwc.terms.Term;
036import org.gbif.dwc.terms.UnknownTerm;
037
038import java.lang.reflect.Field;
039import java.lang.reflect.Modifier;
040import java.net.URI;
041import java.util.ArrayList;
042import java.util.Arrays;
043import java.util.Collections;
044import java.util.Date;
045import java.util.EnumSet;
046import java.util.HashMap;
047import java.util.List;
048import java.util.Map;
049import java.util.Objects;
050import java.util.Optional;
051import java.util.Set;
052import java.util.stream.Collectors;
053import java.util.stream.Stream;
054
055import javax.annotation.Nullable;
056import javax.validation.constraints.Max;
057import javax.validation.constraints.Min;
058import javax.validation.constraints.NotNull;
059
060import com.fasterxml.jackson.annotation.JsonAnyGetter;
061import com.fasterxml.jackson.annotation.JsonIgnore;
062import com.fasterxml.jackson.annotation.JsonProperty;
063import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
064import com.fasterxml.jackson.databind.annotation.JsonSerialize;
065
066import io.swagger.v3.oas.annotations.ExternalDocumentation;
067import io.swagger.v3.oas.annotations.media.Schema;
068import lombok.EqualsAndHashCode;
069import lombok.ToString;
070
071/**
072 * Represents an Occurrence as interpreted by GBIF, adding typed properties on top of the verbatim ones.
073 */
074@EqualsAndHashCode
075@ToString
076@SuppressWarnings("unused")
077public class Occurrence extends VerbatimOccurrence implements LinneanClassification, LinneanClassificationKeys {
078
079  public static final String GEO_DATUM = "WGS84";
080  // keep names of ALL properties of this class in a set for jackson serialization, see #properties()
081  private static final Set<String> PROPERTIES = Collections.unmodifiableSet(
082    Stream.concat(
083      // we need to these JSON properties manually because we have a fixed getter but no field for it
084      Stream.of(DwcTerm.geodeticDatum.simpleName(), "class", DwcTerm.countryCode.simpleName(), GbifTerm.gbifRegion.simpleName(), GbifTerm.publishedByGbifRegion.simpleName()),
085      Stream.concat(Arrays.stream(Occurrence.class.getDeclaredFields()),
086        Arrays.stream(VerbatimOccurrence.class.getDeclaredFields()))
087        .filter(field -> !Modifier.isStatic(field.getModifiers()))
088        .map(Field::getName)).collect(Collectors.toSet()));
089
090  // occurrence fields
091
092  // OpenAPI documentation comes from the enumeration.
093  private BasisOfRecord basisOfRecord;
094
095  @Schema(
096    description = "The number of individuals present at the time of the Occurrence.",
097    externalDocs = @ExternalDocumentation(
098      description = "Darwin Core definition",
099      url = "https://rs.tdwg.org/dwc/terms/individualCount"
100    )
101  )
102  private Integer individualCount;
103
104  // OpenAPI documentation comes from the enumeration.
105  private OccurrenceStatus occurrenceStatus;
106
107  // OpenAPI documentation comes from the enumeration.
108  private Sex sex;
109
110  @Schema(
111    description = "The age class or life stage of the Organism(s) at the time the Occurrence was recorded.\n\n" +
112      "Values are aligned to the [GBIF LifeStage vocabulary](https://registry.gbif.org/vocabulary/LifeStage/concepts)",
113    externalDocs = @ExternalDocumentation(
114      description = "Darwin Core definition",
115      url = "https://rs.tdwg.org/dwc/terms/lifeStage"
116    )
117  )
118  private String lifeStage;
119
120  @Schema(
121    description = "Statement about whether an organism or organisms have been introduced to a given place and time " +
122      "through the direct or indirect activity of modern humans.\n\n" +
123      "Values are aligned to the [GBIF EstablishmentMeans vocabulary](https://registry.gbif.org/vocabulary/EstablishmentMeans/concepts)," +
124      "which is derived from the [Darwin Core EstablishmentMeans vocabulary](https://dwc.tdwg.org/em/).",
125    externalDocs = @ExternalDocumentation(
126      description = "Darwin Core definition",
127      url = "https://rs.tdwg.org/dwc/terms/establishmentMeans"
128    )
129  )
130  private String establishmentMeans;
131
132  @Schema(
133    description = "The degree to which an Organism survives, reproduces, and expands its range at the given " +
134      "place and time.\n\n" +
135      "Values are aligned to the [GBIF DegreeOfEstablishment vocabulary](https://registry.gbif.org/vocabulary/DegreeOfEstablishment/concepts)," +
136      "which is derived from the [Darwin Core DegreeOfEstablishment vocabulary](https://dwc.tdwg.org/doe/).",
137    externalDocs = @ExternalDocumentation(
138      description = "Darwin Core definition",
139      url = "https://rs.tdwg.org/dwc/terms/degreeOfEstablishment"
140    )
141  )
142  private String degreeOfEstablishment;
143
144  @Schema(
145    description = "The process by which an Organism came to be in a given place at a given time.\n\n" +
146    "Values are aligned to the [GBIF Pathway vocabulary](https://registry.gbif.org/vocabulary/Pathway/concepts)," +
147    "which is derived from the [Darwin Core Pathway vocabulary](https://dwc.tdwg.org/pw/).",
148    externalDocs = @ExternalDocumentation(
149      description = "Darwin Core definition",
150      url = "https://rs.tdwg.org/dwc/terms/pathway"
151    )
152  )
153  private String pathway;
154
155  // taxonomy as NUB keys → LinneanClassificationKeys
156
157  @Schema(
158    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the most specific " +
159      "(lowest rank) taxon for this occurrence.  This could be a synonym, see `acceptedTaxonKey`.",
160    externalDocs = @ExternalDocumentation(
161      description = "Darwin Core definition",
162      url = "https://rs.tdwg.org/dwc/terms/"
163    )
164  )
165  private Integer taxonKey;
166
167  @Schema(
168    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the kingdom of this" +
169      "occurrence.",
170    externalDocs = @ExternalDocumentation(
171      description = "Darwin Core definition",
172      url = "https://rs.tdwg.org/dwc/terms/"
173    )
174  )
175  private Integer kingdomKey;
176
177  @Schema(
178    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the phylum of this" +
179      "occurrence.",
180    externalDocs = @ExternalDocumentation(
181      description = "Darwin Core definition",
182      url = "https://rs.tdwg.org/dwc/terms/"
183    )
184  )
185  private Integer phylumKey;
186
187  @Schema(
188    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the class of this" +
189      "occurrence.",
190    externalDocs = @ExternalDocumentation(
191      description = "Darwin Core definition",
192      url = "https://rs.tdwg.org/dwc/terms/"
193    )
194  )
195  private Integer classKey;
196
197  @Schema(
198    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the order of this" +
199      "occurrence.",
200    externalDocs = @ExternalDocumentation(
201      description = "Darwin Core definition",
202      url = "https://rs.tdwg.org/dwc/terms/"
203    )
204  )
205  private Integer orderKey;
206
207  @Schema(
208    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the family of this" +
209      "occurrence.",
210    externalDocs = @ExternalDocumentation(
211      description = "Darwin Core definition",
212      url = "https://rs.tdwg.org/dwc/terms/"
213    )
214  )
215  private Integer familyKey;
216
217  @Schema(
218    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the genus of this" +
219      "occurrence.",
220    externalDocs = @ExternalDocumentation(
221      description = "Darwin Core definition",
222      url = "https://rs.tdwg.org/dwc/terms/"
223    )
224  )
225  private Integer genusKey;
226
227  @Schema(
228    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the subgenus of this" +
229      "occurrence.",
230    externalDocs = @ExternalDocumentation(
231      description = "Darwin Core definition",
232      url = "https://rs.tdwg.org/dwc/terms/"
233    )
234  )
235  private Integer subgenusKey;
236
237  @Schema(
238    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the species of this" +
239      "occurrence.",
240    externalDocs = @ExternalDocumentation(
241      description = "Darwin Core definition",
242      url = "https://rs.tdwg.org/dwc/terms/"
243    )
244  )
245  private Integer speciesKey;
246
247  @Schema(
248    description = "A taxon key from the [GBIF backbone](https://doi.org/10.15468/39omei) for the accepted taxon of " +
249      "this occurrence.",
250    externalDocs = @ExternalDocumentation(
251      description = "Darwin Core definition",
252      url = "https://rs.tdwg.org/dwc/terms/"
253    )
254  )
255  private Integer acceptedTaxonKey;
256
257  // taxonomy as name strings → LinneanClassification
258
259  @Schema(
260    description = "The scientific name (including authorship) for the taxon from the " +
261      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.  This could be a synonym, see " +
262      "also `acceptedScientificName`.",
263    externalDocs = @ExternalDocumentation(
264      description = "Darwin Core definition",
265      url = "https://rs.tdwg.org/dwc/terms/"
266    )
267  )
268  private String scientificName;  // the interpreted name matching taxonKey
269
270  @Schema(
271    description = "The accepted scientific name (including authorship) for the taxon from the " +
272      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
273    externalDocs = @ExternalDocumentation(
274      description = "Darwin Core definition",
275      url = "https://rs.tdwg.org/dwc/terms/"
276    )
277  )
278  private String acceptedScientificName;
279
280  @Schema(
281    description = "The kingdom name (excluding authorship) for the kingdom from the " +
282      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
283    externalDocs = @ExternalDocumentation(
284      description = "Darwin Core definition",
285      url = "https://rs.tdwg.org/dwc/terms/"
286    )
287  )
288  private String kingdom;
289
290  @Schema(
291    description = "The phylum name (excluding authorship) for the phylum from the " +
292      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
293    externalDocs = @ExternalDocumentation(
294      description = "Darwin Core definition",
295      url = "https://rs.tdwg.org/dwc/terms/"
296    )
297  )
298  private String phylum;
299
300  @Schema(
301    description = "The class name (excluding authorship) for the class from the " +
302      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
303    externalDocs = @ExternalDocumentation(
304      description = "Darwin Core definition",
305      url = "https://rs.tdwg.org/dwc/terms/"
306    )
307  )
308  @JsonProperty("class")
309  private String clazz;
310
311  @Schema(
312    description = "The order name (excluding authorship) for the order from the " +
313      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
314    externalDocs = @ExternalDocumentation(
315      description = "Darwin Core definition",
316      url = "https://rs.tdwg.org/dwc/terms/"
317    )
318  )
319  private String order;
320
321  @Schema(
322    description = "The family name (excluding authorship) for the family from the " +
323      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
324    externalDocs = @ExternalDocumentation(
325      description = "Darwin Core definition",
326      url = "https://rs.tdwg.org/dwc/terms/"
327    )
328  )
329  private String family;
330
331  @Schema(
332    description = "The genus name (excluding authorship) for the genus from the " +
333      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
334    externalDocs = @ExternalDocumentation(
335      description = "Darwin Core definition",
336      url = "https://rs.tdwg.org/dwc/terms/"
337    )
338  )
339  private String genus;
340
341  @Schema(
342    description = "The subgenus name (excluding authorship) for the subgenus from the " +
343      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
344    externalDocs = @ExternalDocumentation(
345      description = "Darwin Core definition",
346      url = "https://rs.tdwg.org/dwc/terms/"
347    )
348  )
349  private String subgenus;
350
351  @Schema(
352    description = "The species name (excluding authorship) for the species from the " +
353      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
354    externalDocs = @ExternalDocumentation(
355      description = "Darwin Core definition",
356      url = "https://rs.tdwg.org/dwc/terms/"
357    )
358  )
359  private String species;
360
361  // atomised scientific name
362
363  @Schema(
364    description = "The genus name part of the species name from the " +
365      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
366    externalDocs = @ExternalDocumentation(
367      description = "Darwin Core definition",
368      url = "https://rs.tdwg.org/dwc/terms/genericName"
369    )
370  )
371  private String genericName;
372
373  @Schema(
374    description = "The specific name part of the species name from the " +
375      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
376    externalDocs = @ExternalDocumentation(
377      description = "Darwin Core definition",
378      url = "https://rs.tdwg.org/dwc/terms/specificEpithet"
379    )
380  )
381  private String specificEpithet;
382
383  @Schema(
384    description = "The infraspecific name part of the species name from the " +
385      "[GBIF backbone](https://doi.org/10.15468/39omei) matched to this occurrence.",
386    externalDocs = @ExternalDocumentation(
387      description = "Darwin Core definition",
388      url = "https://rs.tdwg.org/dwc/terms/infraspecificEpithet"
389    )
390  )
391  private String infraspecificEpithet;
392
393  @Schema(
394    description = "The taxonomic rank of the most specific name in the scientificName.",
395    externalDocs = @ExternalDocumentation(
396      description = "Darwin Core definition",
397      url = "https://rs.tdwg.org/dwc/terms/taxonRank"
398    )
399  )
400  private Rank taxonRank;
401
402  @Schema(
403    description = "The status of the use of the scientificName as a label for a taxon.",
404    externalDocs = @ExternalDocumentation(
405      description = "Darwin Core definition",
406      url = "https://rs.tdwg.org/dwc/terms/taxonomicStatus"
407    )
408  )
409  private TaxonomicStatus taxonomicStatus;
410
411  @Schema(
412    description = "The IUCN Red List Category of the taxon of this occurrence.\n\n" +
413      "See the [GBIF vocabulary](https://rs.gbif.org/vocabulary/iucn/threat_status/) for the values and their " +
414      "definitions, and the [IUCN Red List of Threatened Species dataset in GBIF](https://doi.org/10.15468/0qnb58) " +
415      "for the version of the Red List GBIF's interpretation procedures are using.",
416    externalDocs = @ExternalDocumentation(
417      description = "GBIF vocabulary",
418      url = "https://rs.gbif.org/vocabulary/iucn/threat_status/"
419    )
420  )
421  private String iucnRedListCategory;
422
423  // identification
424
425  @Schema(
426    description = "The date on which the subject was determined as representing the Taxon.",
427    externalDocs = @ExternalDocumentation(
428      description = "Darwin Core definition",
429      url = "https://rs.tdwg.org/dwc/terms/dateIdentified"
430    )
431  )
432  private Date dateIdentified;
433
434  // location
435
436  @Schema(
437    description = "The geographic latitude (in decimal degrees, using the WGS84 datum) of the geographic centre " +
438      "of the location of the occurrence.",
439    externalDocs = @ExternalDocumentation(
440      description = "Darwin Core definition",
441      url = "https://rs.tdwg.org/dwc/terms/decimalLatitude"
442    )
443  )
444  private Double decimalLatitude;
445
446  @Schema(
447    description = "The geographic longitude (in decimal degrees, using the WGS84 datum) of the geographic centre " +
448      "of the location of the occurrence.",
449    externalDocs = @ExternalDocumentation(
450      description = "Darwin Core definition",
451      url = "https://rs.tdwg.org/dwc/terms/decimalLongitude"
452    )
453  )
454  private Double decimalLongitude;
455
456  //coordinatePrecision and coordinateUncertaintyInMeters should be BigDecimal see POR-2795
457
458  @Schema(
459    description = "A decimal representation of the precision of the coordinates given in the decimalLatitude and decimalLongitude.",
460    externalDocs = @ExternalDocumentation(
461      description = "Darwin Core definition",
462      url = "https://rs.tdwg.org/dwc/terms/coordinatePrecision"
463    )
464  )
465  private Double coordinatePrecision;
466
467  @Schema(
468    description = "The horizontal distance (in metres) from the given decimalLatitude and decimalLongitude " +
469      "describing the smallest circle containing the whole of the Location.",
470    externalDocs = @ExternalDocumentation(
471      description = "Darwin Core definition",
472      url = "https://rs.tdwg.org/dwc/terms/coordinateUncertaintyInMeters"
473    )
474  )
475  private Double coordinateUncertaintyInMeters;
476
477  @Schema(
478    description = "**Deprecated.**  This value is always null.  It is an obsolete Darwin Core term.",
479    externalDocs = @ExternalDocumentation(
480      description = "Darwin Core definition",
481      url = "https://rs.tdwg.org/dwc/terms/"
482    )
483  )
484  @Deprecated //see getter
485  private Double coordinateAccuracy;
486
487  @Schema(
488    description = "Elevation (altitude) in metres above sea level.  This is not a current Darwin Core term."
489  )
490  private Double elevation;
491
492  @Schema(
493    description = "The value of the potential error associated with the elevation.  This is not a current Darwin Core term."
494  )
495  private Double elevationAccuracy;
496
497  @Schema(
498    description = "Depth in metres below sea level.  This is not a current Darwin Core term."
499  )
500  private Double depth;
501
502  @Schema(
503    description = "The value of the potential error associated with the depth.  This is not a current Darwin Core term."
504  )
505  private Double depthAccuracy;
506
507  // OpenAPI documentation from enumeration
508  private Continent continent;
509
510  @JsonSerialize(using = Country.IsoSerializer.class)
511  @JsonDeserialize(using = Country.IsoDeserializer.class)
512  private Country country;
513
514  @Schema(
515    description = "The name of the next-smaller administrative region than country (state, province, canton, " +
516      "department, region, etc.) in which the occurrence occurs.\n\n" +
517      "This value is unaltered by GBIF's processing; see also the GADM fields.",
518    externalDocs = @ExternalDocumentation(
519      description = "Darwin Core definition",
520      url = "https://rs.tdwg.org/dwc/terms/stateProvince"
521    )
522  )
523  private String stateProvince;
524
525  @Schema(
526    description = "The administrative divisions according to the [GADM database](https://gadm.org/).\n\n" +
527      "This value is applied by GBIF's processing without consideration of the `stateProvince`, `county` or `locality` fields."
528  )
529  private Gadm gadm = new Gadm();
530
531  @Schema(
532    description = "The name of the water body in which the Location occurs.",
533    externalDocs = @ExternalDocumentation(
534      description = "Darwin Core definition",
535      url = "https://rs.tdwg.org/dwc/terms/waterBody"
536    )
537  )
538  private String waterBody;
539
540  @Schema(
541    description = "The distance in metres of the occurrence from a centroid known to be applied to occurrences " +
542      "during georeferencing.  This can potentially indicate low-precision georeferencing, check the values of " +
543      "`coordinateUncertaintyInMeters` and `georeferenceRemarks`."
544  )
545  private Double distanceFromCentroidInMeters;
546
547  @Schema(
548    description = "A list (concatenated and separated) of geographic names less specific than the information captured in the dwc:locality term.",
549    externalDocs = @ExternalDocumentation(
550      description = "Darwin Core definition",
551      url = "https://rs.tdwg.org/dwc/terms/higherGeography"
552    )
553  )
554  private String higherGeography;
555
556  @Schema(
557    description = "A list (concatenated and separated) of names of people, groups, or organizations who determined the georeference (spatial representation) for the dcterms:Location.",
558    externalDocs = @ExternalDocumentation(
559      description = "Darwin Core definition",
560      url = "https://rs.tdwg.org/dwc/terms/georeferencedBy"
561    )
562  )
563  private String georeferencedBy;
564
565  // recording event
566
567  @Schema(
568    description = "The four-digit year in which the event occurred, according to the Common Era calendar.",
569    externalDocs = @ExternalDocumentation(
570      description = "Darwin Core definition",
571      url = "https://rs.tdwg.org/dwc/terms/year"
572    )
573  )
574  private Integer year;
575
576  @Schema(
577    description = "The integer month in which the Event occurred.",
578    externalDocs = @ExternalDocumentation(
579      description = "Darwin Core definition",
580      url = "https://rs.tdwg.org/dwc/terms/month"
581    )
582  )
583  private Integer month;
584
585  @Schema(
586    description = "The integer day of the month on which the Event occurred.",
587    externalDocs = @ExternalDocumentation(
588      description = "Darwin Core definition",
589      url = "https://rs.tdwg.org/dwc/terms/day"
590    )
591  )
592  private Integer day;
593
594  @Schema(
595    description = "The date-time during which an Event occurred. For occurrences, this is the date-time when the " +
596      "event was recorded. Not suitable for a time in a geological context.",
597    externalDocs = @ExternalDocumentation(
598      description = "Darwin Core definition",
599      url = "https://rs.tdwg.org/dwc/terms/eventDate"
600    )
601  )
602  private IsoDateInterval eventDate;
603
604  @Schema(
605    description = "The latest integer day of the year on which the Event occurred (1 for 1 January, 365 for " +
606      "31 December, except in a leap year, in which case it is 366).",
607    externalDocs = @ExternalDocumentation(
608      description = "Darwin Core definition",
609      url = "https://rs.tdwg.org/dwc/terms/endDayOfYear"
610    )
611  )
612  private Integer startDayOfYear;
613
614  @Schema(
615    description = "The earliest integer day of the year on which the Event occurred (1 for 1 January, 365 for " +
616      "31 December, except in a leap year, in which case it is 366).",
617    externalDocs = @ExternalDocumentation(
618      description = "Darwin Core definition",
619      url = "https://rs.tdwg.org/dwc/terms/startDayOfYear"
620    )
621  )
622  private Integer endDayOfYear;
623
624  @Schema(
625    description = "A list (concatenated and separated) of nomenclatural types (type status, typified scientific name, " +
626      "publication) applied to the occurrence.",
627    externalDocs = @ExternalDocumentation(
628      description = "Darwin Core definition",
629      url = "https://rs.tdwg.org/dwc/terms/typeStatus"
630    )
631  )
632  private String typeStatus;
633
634  // extracted from type status, but we should propose a new dwc term for this!
635  // for example: "Paratype of Taeniopteryx metequi Ricker & Ross" is status=Paratype, typifiedName=Taeniopteryx metequi Ricker & Ross
636  @Schema(
637    description = "The scientific name that is based on the type specimen.\n\n" +
638      "This is not yet a Darwin Core term, see the [proposal to add it](https://github.com/tdwg/dwc/issues/28)."
639  )
640  private String typifiedName; // missing from DwC
641
642  @Schema(
643    description = "A specific interpretation issue found during processing and interpretation of the record.\n\n" +
644      "See the https://links.gbif.org/occurrence-issues[list of occurrence issues] and the " +
645      "https://gbif.github.io/gbif-api/apidocs/org/gbif/api/vocabulary/OccurrenceIssue.html[OccurrenceIssue enumeration] " +
646      "for possible values and definitions."
647  )
648  private Set<OccurrenceIssue> issues = EnumSet.noneOf(OccurrenceIssue.class);
649
650  // record level
651
652  @Schema(
653    description = "The most recent date-time on which the occurrence was changed, according to the publisher.",
654    externalDocs = @ExternalDocumentation(
655      description = "Dublin Core definition",
656      url = "https://purl.org/dc/terms/modified"
657    )
658  )
659  private Date modified;  // interpreted dc:modified, i.e. date changed in source
660
661  @Schema(
662    description = "The time this occurrence was last processed by GBIF's interpretation system “Pipelines”.\n\n" +
663      "This is the time the record was last changed in GBIF, **not** the time the record was last changed by the " +
664      "publisher.  Data is also reprocessed when we changed the taxonomic backbone, geographic data sources or " +
665      "other interpretation procedures.\n\n" +
666      "An earlier interpretation system distinguished between “parsing” and “interpretation”, but in the current " +
667      "system there is only one process — the two dates will always be the same."
668  )
669  private Date lastInterpreted;
670
671  @Schema(
672    description = "A related resource that is referenced, cited, or otherwise pointed to by the described resource.",
673    externalDocs = @ExternalDocumentation(
674      description = "Dublin Core definition",
675      url = "https://purl.org/dc/terms/references"
676    )
677  )
678  private URI references;
679
680  @Schema(
681    description = "A legal document giving official permission to do something with the occurrence.",
682    externalDocs = @ExternalDocumentation(
683      description = "Dublin Core definition",
684      url = "https://purl.org/dc/terms/license"
685    )
686  )
687  private License license;
688
689  @Schema(
690    description = "A number or enumeration value for the quantity of organisms.",
691    externalDocs = @ExternalDocumentation(
692      description = "Darwin Core definition",
693      url = "https://rs.tdwg.org/dwc/terms/organismQuantity"
694    )
695  )
696  private Double organismQuantity;
697
698  @Schema(
699    description = "The type of quantification system used for the quantity of organisms.",
700    externalDocs = @ExternalDocumentation(
701      description = "Darwin Core definition",
702      url = "https://rs.tdwg.org/dwc/terms/organismQuantityType"
703    )
704  )
705  private String organismQuantityType;
706
707  @Schema(
708    description = "The unit of measurement of the size (time duration, length, area, or volume) of a sample in a sampling event.",
709    externalDocs = @ExternalDocumentation(
710      description = "Darwin Core definition",
711      url = "https://rs.tdwg.org/dwc/terms/sampleSizeUnit"
712    )
713  )
714  private String sampleSizeUnit;
715
716  @Schema(
717    description = "A numeric value for a measurement of the size (time duration, length, area, or volume) of a sample in a sampling event.",
718    externalDocs = @ExternalDocumentation(
719      description = "Darwin Core definition",
720      url = "https://rs.tdwg.org/dwc/terms/sampleSizeValue"
721    )
722  )
723  private Double sampleSizeValue;
724
725  @Schema(
726    description = "The relative measurement of the quantity of the organism (i.e. without absolute units)."
727  )
728  private Double relativeOrganismQuantity;
729
730  @Schema(
731    description = "Flag occurrence when associatedSequences/extension exists"
732  )
733  private boolean isSequenced;
734
735  @Schema(
736      description = "A list (concatenated and separated) of identifiers (publication, global unique identifier, URI) "
737        + "of genetic sequence information associated with the material entity.",
738      externalDocs =
739          @ExternalDocumentation(
740              description = "Darwin Core definition",
741              url = "https://rs.tdwg.org/dwc/terms/associatedSequences"))
742  private String associatedSequences;
743
744  // interpreted extension data
745
746  @Schema(
747    description = "Alternative identifiers for the occurrence.",
748    externalDocs = @ExternalDocumentation(
749      description = "GBIF Alternative Identifiers extension",
750      url = "https://rs.gbif.org/terms/1.0/Identifier"
751    )
752  )
753  private List<Identifier> identifiers = new ArrayList<>();
754
755  @Schema(
756    description = "Multimedia related to te occurrence.",
757    externalDocs = @ExternalDocumentation(
758      description = "GBIF Multimedia extension",
759      url = "https://rs.gbif.org/terms/1.0/Multimedia"
760    )
761  )
762  private List<MediaObject> media = new ArrayList<>();
763
764  @Schema(
765    description = "Measurements or facts about the the occurrence.",
766    externalDocs = @ExternalDocumentation(
767      description = "Darwin Core definition",
768      url = "https://rs.tdwg.org/dwc/terms/MeasurementOrFact"
769    )
770  )
771  private List<MeasurementOrFact> facts = new ArrayList<>();
772
773  @Schema(
774    description = "Relationships between occurrences.",
775    externalDocs = @ExternalDocumentation(
776      description = "Darwin Core definition",
777      url = "https://rs.tdwg.org/dwc/terms/ResourceRelationship"
778    )
779  )
780  private List<OccurrenceRelation> relations = new ArrayList<>();
781
782  @Schema(
783    description = "A list of the globally unique identifiers for the person, people, groups, or organizations " +
784      "responsible for recording the original Occurrence.",
785    externalDocs = @ExternalDocumentation(
786      description = "Darwin Core definition",
787      url = "https://rs.tdwg.org/dwc/terms/recordedByID"
788    )
789  )
790  @JsonProperty("recordedByIDs")
791  private List<AgentIdentifier> recordedByIds = new ArrayList<>();
792
793  @Schema(
794    description = "A list of the globally unique identifiers for the person, people, groups, or organizations " +
795      "responsible for assigning the Taxon to the occurrence.",
796    externalDocs = @ExternalDocumentation(
797      description = "Darwin Core definition",
798      url = "https://rs.tdwg.org/dwc/terms/identifiedByID"
799    )
800  )
801  @JsonProperty("identifiedByIDs")
802  private List<AgentIdentifier> identifiedByIds = new ArrayList<>();
803
804  @Schema(
805    description = "**Experimental.**  The UUID of the institution holding the specimen occurrence, from GRSciColl."
806  )
807  @Experimental
808  private String institutionKey;
809
810  @Schema(
811    description = "**Experimental.**  The UUID of the collection containing the specimen occurrence, from GRSciColl."
812  )
813  @Experimental
814  private String collectionKey;
815
816  @Schema(
817    description = "**Experimental.**  Whether the occurrence belongs to a machine-calculated cluster of probable " +
818      "duplicate occurrences.",
819    externalDocs = @ExternalDocumentation(
820      description = "GBIF Data Blog",
821      url = "https://data-blog.gbif.org/post/clustering-occurrences/"
822    )
823  )
824  @Experimental
825  private boolean isInCluster;
826
827  @Schema(
828    description = "An identifier for the set of data. May be a global unique identifier or an identifier specific to " +
829      "a collection or institution.",
830    externalDocs = @ExternalDocumentation(
831      description = "Darwin Core definition",
832      url = "https://rs.tdwg.org/dwc/terms/datasetID"
833    )
834  )
835  private String datasetID;
836
837  @Schema(
838    description = "The name identifying the data set from which the record was derived.",
839    externalDocs = @ExternalDocumentation(
840      description = "Darwin Core definition",
841      url = "https://rs.tdwg.org/dwc/terms/"
842    )
843  )
844  private String datasetName;
845
846  @Schema(
847    description = "A list (concatenated and separated) of previous or alternate fully qualified catalogue numbers " +
848      "or other human-used identifiers for the same occurrence, whether in the current or any other data set or collection.",
849    externalDocs = @ExternalDocumentation(
850      description = "Darwin Core definition",
851      url = "https://rs.tdwg.org/dwc/terms/otherCatalogNumbers"
852    )
853  )
854  private String otherCatalogNumbers;
855
856  @Schema(
857    description = "The full name of the earliest possible geochronologic eon or lowest chrono-stratigraphic eonothem or the informal name (\"Precambrian\") attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
858    externalDocs = @ExternalDocumentation(
859      description = "Darwin Core definition",
860      url = "https://rs.tdwg.org/dwc/terms/earliestEonOrLowestEonothem"
861    )
862  )
863  private String earliestEonOrLowestEonothem;
864
865  @Schema(
866    description = "The full name of the latest possible geochronologic eon or highest chrono-stratigraphic eonothem or the informal name (\"Precambrian\") attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
867    externalDocs = @ExternalDocumentation(
868      description = "Darwin Core definition",
869      url = "https://rs.tdwg.org/dwc/terms/latestEonOrHighestEonothem"
870    )
871  )
872  private String latestEonOrHighestEonothem;
873
874  @Schema(
875    description = "The full name of the earliest possible geochronologic era or lowest chronostratigraphic erathem attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
876    externalDocs = @ExternalDocumentation(
877      description = "Darwin Core definition",
878      url = "https://rs.tdwg.org/dwc/terms/earliestEraOrLowestErathem"
879    )
880  )
881  private String earliestEraOrLowestErathem;
882
883  @Schema(
884    description = "The full name of the latest possible geochronologic era or highest chronostratigraphic erathem attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
885    externalDocs = @ExternalDocumentation(
886      description = "Darwin Core definition",
887      url = "https://rs.tdwg.org/dwc/terms/latestEraOrHighestErathem"
888    )
889  )
890  private String latestEraOrHighestErathem;
891
892  @Schema(
893    description = "The full name of the earliest possible geochronologic period or lowest chronostratigraphic system attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
894    externalDocs = @ExternalDocumentation(
895      description = "Darwin Core definition",
896      url = "https://rs.tdwg.org/dwc/terms/earliestPeriodOrLowestSystem"
897    )
898  )
899  private String earliestPeriodOrLowestSystem;
900
901  @Schema(
902    description = "The full name of the latest possible geochronologic period or highest chronostratigraphic system attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
903    externalDocs = @ExternalDocumentation(
904      description = "Darwin Core definition",
905      url = "https://rs.tdwg.org/dwc/terms/latestPeriodOrHighestSystem"
906    )
907  )
908  private String latestPeriodOrHighestSystem;
909
910  @Schema(
911    description = "The full name of the earliest possible geochronologic epoch or lowest chronostratigraphic series attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
912    externalDocs = @ExternalDocumentation(
913      description = "Darwin Core definition",
914      url = "https://rs.tdwg.org/dwc/terms/earliestEpochOrLowestSeries"
915    )
916  )
917  private String earliestEpochOrLowestSeries;
918
919  @Schema(
920    description = "The full name of the latest possible geochronologic epoch or highest chronostratigraphic series attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
921    externalDocs = @ExternalDocumentation(
922      description = "Darwin Core definition",
923      url = "https://rs.tdwg.org/dwc/terms/latestEpochOrHighestSeries"
924    )
925  )
926  private String latestEpochOrHighestSeries;
927
928  @Schema(
929    description = "The full name of the earliest possible geochronologic age or lowest chronostratigraphic stage attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
930    externalDocs = @ExternalDocumentation(
931      description = "Darwin Core definition",
932      url = "https://rs.tdwg.org/dwc/terms/earliestAgeOrLowestStage"
933    )
934  )
935  private String earliestAgeOrLowestStage;
936
937  @Schema(
938    description = "The full name of the latest possible geochronologic age or highest chronostratigraphic stage attributable to the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
939    externalDocs = @ExternalDocumentation(
940      description = "Darwin Core definition",
941      url = "https://rs.tdwg.org/dwc/terms/latestAgeOrHighestStage"
942    )
943  )
944  private String latestAgeOrHighestStage;
945
946  @Schema(
947    description = "The full name of the lowest possible geological biostratigraphic zone of the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
948    externalDocs = @ExternalDocumentation(
949      description = "Darwin Core definition",
950      url = "https://rs.tdwg.org/dwc/terms/lowestBiostratigraphicZone"
951    )
952  )
953  private String lowestBiostratigraphicZone;
954
955  @Schema(
956    description = "The full name of the highest possible geological biostratigraphic zone of the stratigraphic horizon from which the dwc:MaterialEntity was collected.",
957    externalDocs = @ExternalDocumentation(
958      description = "Darwin Core definition",
959      url = "https://rs.tdwg.org/dwc/terms/highestBiostratigraphicZone"
960    )
961  )
962  private String highestBiostratigraphicZone;
963
964  @Schema(
965    description = "The full name of the lithostratigraphic group from which the dwc:MaterialEntity was collected.",
966    externalDocs = @ExternalDocumentation(
967      description = "Darwin Core definition",
968      url = "https://rs.tdwg.org/dwc/terms/group"
969    )
970  )
971  private String group;
972
973  @Schema(
974    description = "The full name of the lithostratigraphic formation from which the dwc:MaterialEntity was collected.",
975    externalDocs = @ExternalDocumentation(
976      description = "Darwin Core definition",
977      url = "https://rs.tdwg.org/dwc/terms/formation"
978    )
979  )
980  private String formation;
981
982  @Schema(
983    description = "The full name of the lithostratigraphic member from which the dwc:MaterialEntity was collected.",
984    externalDocs = @ExternalDocumentation(
985      description = "Darwin Core definition",
986      url = "https://rs.tdwg.org/dwc/terms/member"
987    )
988  )
989  private String member;
990
991  @Schema(
992    description = "The full name of the lithostratigraphic bed from which the dwc:MaterialEntity was collected.",
993    externalDocs = @ExternalDocumentation(
994      description = "Darwin Core definition",
995      url = "https://rs.tdwg.org/dwc/terms/bed"
996    )
997  )
998  private String bed;
999
1000
1001  @Schema(
1002    description = "A person, group, or organization responsible for recording the original occurrence.",
1003    externalDocs = @ExternalDocumentation(
1004      description = "Darwin Core definition",
1005      url = "https://rs.tdwg.org/dwc/terms/recordedBy"
1006    )
1007  )
1008  private String recordedBy;
1009
1010  @Schema(
1011    description = "A list (concatenated and separated) of names of people, groups, or organizations who assigned the " +
1012      "Taxon to the occurrence.",
1013    externalDocs = @ExternalDocumentation(
1014      description = "Darwin Core definition",
1015      url = "https://rs.tdwg.org/dwc/terms/identifiedBy"
1016    )
1017  )
1018  private String identifiedBy;
1019
1020  @Schema(
1021    description = "A preparation or preservation method for a specimen.",
1022    externalDocs = @ExternalDocumentation(
1023      description = "Darwin Core definition",
1024      url = "https://rs.tdwg.org/dwc/terms/preparations"
1025    )
1026  )
1027  private String preparations;
1028
1029  @Schema(
1030    description = "The methods or protocols used during an Event, denoted by an IRI.",
1031    externalDocs = @ExternalDocumentation(
1032      description = "Darwin Core definition",
1033      url = "https://rs.tdwg.org/dwc/terms/samplingProtocol"
1034    )
1035  )
1036  private String samplingProtocol;
1037
1038  public Occurrence() {
1039
1040  }
1041
1042  /**
1043   * Create occurrence instance from existing verbatim one, copying over all data.
1044   */
1045  public Occurrence(@Nullable VerbatimOccurrence verbatim) {
1046    if (verbatim != null) {
1047      setKey(verbatim.getKey());
1048      setDatasetKey(verbatim.getDatasetKey());
1049      setPublishingOrgKey(verbatim.getPublishingOrgKey());
1050      setPublishingCountry(verbatim.getPublishingCountry());
1051      setProtocol(verbatim.getProtocol());
1052      setCrawlId(verbatim.getCrawlId());
1053      if (verbatim.getLastCrawled() != null) {
1054        setLastCrawled(new Date(verbatim.getLastCrawled().getTime()));
1055      }
1056      if (verbatim.getVerbatimFields() != null) {
1057        getVerbatimFields().putAll(verbatim.getVerbatimFields());
1058      }
1059      if (verbatim.getLastParsed() != null) {
1060        setLastParsed(verbatim.getLastParsed());
1061      }
1062      setExtensions(verbatim.getExtensions());
1063    }
1064  }
1065
1066  @Nullable
1067  public BasisOfRecord getBasisOfRecord() {
1068    return basisOfRecord;
1069  }
1070
1071  public void setBasisOfRecord(BasisOfRecord basisOfRecord) {
1072    this.basisOfRecord = basisOfRecord;
1073  }
1074
1075  @Nullable
1076  public Integer getIndividualCount() {
1077    return individualCount;
1078  }
1079
1080  public void setIndividualCount(Integer individualCount) {
1081    this.individualCount = individualCount;
1082  }
1083
1084  @Nullable
1085  public OccurrenceStatus getOccurrenceStatus() {
1086    return occurrenceStatus;
1087  }
1088
1089  public void setOccurrenceStatus(OccurrenceStatus occurrenceStatus) {
1090    this.occurrenceStatus = occurrenceStatus;
1091  }
1092
1093  @Nullable
1094  public Sex getSex() {
1095    return sex;
1096  }
1097
1098  public void setSex(Sex sex) {
1099    this.sex = sex;
1100  }
1101
1102  @Nullable
1103  public String getLifeStage() {
1104    return lifeStage;
1105  }
1106
1107  public void setLifeStage(String lifeStage) {
1108    this.lifeStage = lifeStage;
1109  }
1110
1111  @Nullable
1112  public String getEstablishmentMeans() {
1113    return establishmentMeans;
1114  }
1115
1116  public void setEstablishmentMeans(String establishmentMeans) {
1117    this.establishmentMeans = establishmentMeans;
1118  }
1119
1120  /**
1121   * The best matching, accepted GBIF backbone name usage representing this occurrence.
1122   * In case the verbatim scientific name and its classification can only be matched to a higher rank this will
1123   * represent the lowest matching rank. In the worst case this could just be for example Animalia.
1124   */
1125  @Nullable
1126  public Integer getTaxonKey() {
1127    return taxonKey;
1128  }
1129
1130  public void setTaxonKey(Integer taxonKey) {
1131    this.taxonKey = taxonKey;
1132  }
1133
1134  @Nullable
1135  @Override
1136  public Integer getKingdomKey() {
1137    return kingdomKey;
1138  }
1139
1140  @Override
1141  public void setKingdomKey(@Nullable Integer kingdomKey) {
1142    this.kingdomKey = kingdomKey;
1143  }
1144
1145  @Nullable
1146  @Override
1147  public Integer getPhylumKey() {
1148    return phylumKey;
1149  }
1150
1151  @Override
1152  public void setPhylumKey(@Nullable Integer phylumKey) {
1153    this.phylumKey = phylumKey;
1154  }
1155
1156  @Nullable
1157  @Override
1158  public Integer getClassKey() {
1159    return classKey;
1160  }
1161
1162  @Override
1163  public void setClassKey(@Nullable Integer classKey) {
1164    this.classKey = classKey;
1165  }
1166
1167  @Nullable
1168  @Override
1169  public Integer getOrderKey() {
1170    return orderKey;
1171  }
1172
1173  @Override
1174  public void setOrderKey(@Nullable Integer orderKey) {
1175    this.orderKey = orderKey;
1176  }
1177
1178  @Nullable
1179  @Override
1180  public Integer getFamilyKey() {
1181    return familyKey;
1182  }
1183
1184  @Override
1185  public void setFamilyKey(@Nullable Integer familyKey) {
1186    this.familyKey = familyKey;
1187  }
1188
1189  @Nullable
1190  @Override
1191  public Integer getGenusKey() {
1192    return genusKey;
1193  }
1194
1195  @Override
1196  public void setGenusKey(@Nullable Integer genusKey) {
1197    this.genusKey = genusKey;
1198  }
1199
1200  @Nullable
1201  @Override
1202  public Integer getSubgenusKey() {
1203    return subgenusKey;
1204  }
1205
1206  @Override
1207  public void setSubgenusKey(@Nullable Integer subgenusKey) {
1208    this.subgenusKey = subgenusKey;
1209  }
1210
1211  @Nullable
1212  @Override
1213  public Integer getHigherRankKey(Rank rank) {
1214    return ClassificationUtils.getHigherRankKey(this, rank);
1215  }
1216
1217  /**
1218   * An ordered map with entries for all higher Linnean ranks excluding the taxonKey itself.
1219   * The map starts with the highest rank, e.g. the kingdom and maps the name usage key to its canonical name.
1220   *
1221   * @return map of higher ranks
1222   */
1223  @NotNull
1224  @JsonIgnore
1225  public Map<Integer, String> getHigherClassificationMap() {
1226    return taxonKey == null ? ClassificationUtils.getHigherClassificationMap(this)
1227      : ClassificationUtils.getHigherClassificationMap(this, taxonKey, null, null);
1228  }
1229
1230  /**
1231   * The accepted species for this occurrence. In case the taxonKey is of a higher rank than species (e.g. genus)
1232   * speciesKey is null. In case taxonKey represents an infraspecific taxon the speciesKey points to the species
1233   * the infraspecies is classified as. In case of taxonKey being a species the speciesKey is the same.
1234   */
1235  @Nullable
1236  @Override
1237  public Integer getSpeciesKey() {
1238    return speciesKey;
1239  }
1240
1241  @Override
1242  public void setSpeciesKey(@Nullable Integer speciesKey) {
1243    this.speciesKey = speciesKey;
1244  }
1245
1246  /**
1247   * The accepted taxon key from the GBIF backbone.
1248   */
1249  @Nullable
1250  public Integer getAcceptedTaxonKey() {
1251    return acceptedTaxonKey;
1252  }
1253
1254  public void setAcceptedTaxonKey(Integer acceptedTaxonKey) {
1255    this.acceptedTaxonKey = acceptedTaxonKey;
1256  }
1257
1258  @Nullable
1259  public String getSpecificEpithet() {
1260    return specificEpithet;
1261  }
1262
1263  public void setSpecificEpithet(String specificEpithet) {
1264    this.specificEpithet = specificEpithet;
1265  }
1266
1267  @Nullable
1268  public String getInfraspecificEpithet() {
1269    return infraspecificEpithet;
1270  }
1271
1272  public void setInfraspecificEpithet(String infraspecificEpithet) {
1273    this.infraspecificEpithet = infraspecificEpithet;
1274  }
1275
1276  @Nullable
1277  public Rank getTaxonRank() {
1278    return taxonRank;
1279  }
1280
1281  public void setTaxonRank(Rank taxonRank) {
1282    this.taxonRank = taxonRank;
1283  }
1284
1285  /**
1286   * The status of the use of the scientificName as a label for a taxon.
1287   * The GBIF recommended controlled value vocabulary can be found at <a href="http://rs.gbif.org/vocabulary/gbif/taxonomic_status.xml">http://rs.gbif.org/vocabulary/gbif/taxonomic_status.xm</a>.
1288   */
1289  @Nullable
1290  public TaxonomicStatus getTaxonomicStatus() {
1291    return taxonomicStatus;
1292  }
1293
1294  public void setTaxonomicStatus(TaxonomicStatus taxonomicStatus) {
1295    this.taxonomicStatus = taxonomicStatus;
1296  }
1297
1298  /**
1299   * The IUCN Red List Category.
1300   */
1301  @Nullable
1302  public String getIucnRedListCategory() {
1303    return iucnRedListCategory;
1304  }
1305
1306  public void setIucnRedListCategory(String iucnRedListCategory) {
1307    this.iucnRedListCategory = iucnRedListCategory;
1308  }
1309
1310  /**
1311   * The scientific name for taxonKey from the GBIF backbone.
1312   */
1313  @Nullable
1314  public String getScientificName() {
1315    return scientificName;
1316  }
1317
1318  public void setScientificName(@Nullable String scientificName) {
1319    this.scientificName = scientificName;
1320  }
1321
1322  /**
1323   * The verbatim scientific name as provided by the source.
1324   */
1325  @Nullable
1326  @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
1327  public String getVerbatimScientificName() {
1328    return getVerbatimField(DwcTerm.scientificName);
1329  }
1330
1331  public void setVerbatimScientificName(String scientificName) {
1332    //DO NOTHING
1333  }
1334
1335  /**
1336   * The accepted scientific name for the acceptedTaxonKey from the GBIF backbone.
1337   */
1338  @Nullable
1339  public String getAcceptedScientificName() {
1340    return acceptedScientificName;
1341  }
1342
1343  public void setAcceptedScientificName(String acceptedScientificName) {
1344    this.acceptedScientificName = acceptedScientificName;
1345  }
1346
1347  @Nullable
1348  @Override
1349  public String getKingdom() {
1350    return kingdom;
1351  }
1352
1353  @Override
1354  public void setKingdom(@Nullable String kingdom) {
1355    this.kingdom = kingdom;
1356  }
1357
1358  @Nullable
1359  @Override
1360  public String getPhylum() {
1361    return phylum;
1362  }
1363
1364  @Override
1365  public void setPhylum(@Nullable String phylum) {
1366    this.phylum = phylum;
1367  }
1368
1369  @Nullable
1370  @Override
1371  public String getClazz() {
1372    return clazz;
1373  }
1374
1375  @Override
1376  public void setClazz(@Nullable String clazz) {
1377    this.clazz = clazz;
1378  }
1379
1380  @Nullable
1381  @Override
1382  public String getOrder() {
1383    return order;
1384  }
1385
1386  @Override
1387  public void setOrder(@Nullable String order) {
1388    this.order = order;
1389  }
1390
1391  @Nullable
1392  @Override
1393  public String getFamily() {
1394    return family;
1395  }
1396
1397  @Override
1398  public void setFamily(@Nullable String family) {
1399    this.family = family;
1400  }
1401
1402  @Nullable
1403  @Override
1404  public String getGenus() {
1405    return genus;
1406  }
1407
1408  @Override
1409  public void setGenus(@Nullable String genus) {
1410    this.genus = genus;
1411  }
1412
1413  @Nullable
1414  public String getGenericName() {
1415    return genericName;
1416  }
1417
1418  public void setGenericName(String genericName) {
1419    this.genericName = genericName;
1420  }
1421
1422  @Nullable
1423  @Override
1424  public String getSubgenus() {
1425    return subgenus;
1426  }
1427
1428  @Override
1429  public void setSubgenus(@Nullable String subgenus) {
1430    this.subgenus = subgenus;
1431  }
1432
1433  @Nullable
1434  @Override
1435  public String getHigherRank(Rank rank) {
1436    return ClassificationUtils.getHigherRank(this, rank);
1437  }
1438
1439  /**
1440   * The corresponding scientific name of the speciesKey from the GBIF backbone.
1441   */
1442  @Nullable
1443  @Override
1444  public String getSpecies() {
1445    return species;
1446  }
1447
1448  @Override
1449  public void setSpecies(@Nullable String species) {
1450    this.species = species;
1451  }
1452
1453  @Nullable
1454  public Date getDateIdentified() {
1455    return dateIdentified == null ? null : new Date(dateIdentified.getTime());
1456  }
1457
1458  public void setDateIdentified(@Nullable Date dateIdentified) {
1459    this.dateIdentified = dateIdentified == null ? null : new Date(dateIdentified.getTime());
1460  }
1461
1462  /**
1463   * The decimalLongitude in decimal degrees always for the WGS84 datum. If a different geodetic datum was given the verbatim
1464   * coordinates are transformed into WGS84 values.
1465   */
1466  @Nullable
1467  public Double getDecimalLongitude() {
1468    return decimalLongitude;
1469  }
1470
1471  public void setDecimalLongitude(@Nullable Double decimalLongitude) {
1472    this.decimalLongitude = decimalLongitude;
1473  }
1474
1475  @Nullable
1476  public Double getDecimalLatitude() {
1477    return decimalLatitude;
1478  }
1479
1480  public void setDecimalLatitude(@Nullable Double decimalLatitude) {
1481    this.decimalLatitude = decimalLatitude;
1482  }
1483
1484  /**
1485   * The uncertainty radius for lat/lon in meters.
1486   */
1487  @Nullable
1488  public Double getCoordinateUncertaintyInMeters() {
1489    return coordinateUncertaintyInMeters;
1490  }
1491
1492  public void setCoordinateUncertaintyInMeters(@Nullable Double coordinateUncertaintyInMeters) {
1493    this.coordinateUncertaintyInMeters = coordinateUncertaintyInMeters;
1494  }
1495
1496  @Nullable
1497  public Double getCoordinatePrecision() {
1498    return coordinatePrecision;
1499  }
1500
1501  public void setCoordinatePrecision(Double coordinatePrecision) {
1502    this.coordinatePrecision = coordinatePrecision;
1503  }
1504
1505  /**
1506   * @deprecated to be removed in the public v2 of the API (see POR-3061)
1507   * The uncertainty for latitude in decimal degrees.
1508   * Note that the longitude degrees have a different accuracy in degrees which changes with latitude and is largest at the poles.
1509   */
1510  @Nullable
1511  @Deprecated
1512  public Double getCoordinateAccuracy() {
1513    return coordinateAccuracy;
1514  }
1515
1516  public void setCoordinateAccuracy(@Nullable Double coordinateAccuracy) {
1517    this.coordinateAccuracy = coordinateAccuracy;
1518  }
1519
1520  /**
1521   * The geodetic datum for the interpreted decimal coordinates.
1522   * This is always WGS84 if a coordinate exists as we reproject other datums into WGS84.
1523   */
1524  @Schema(
1525    description = "The geodetic datum for the interpreted decimal coordinates.\n\n" +
1526      "Coordinates are reprojected to WGS84 if they exist, so this field is either null or `WGS84`."
1527  )
1528  @Nullable
1529  public String getGeodeticDatum() {
1530    if (decimalLatitude != null) {
1531      return GEO_DATUM;
1532    }
1533    return null;
1534  }
1535
1536  /**
1537   * This private method is needed for jackson deserialization only.
1538   */
1539  private void setGeodeticDatum(String datum) {
1540    // ignore, we have a static WGS84 value
1541  }
1542
1543  /**
1544   * Elevation in meters usually above sea level (altitude).
1545   * </br>
1546   * The elevation is calculated using the equation: (minimumElevationInMeters + maximumElevationInMeters) / 2.
1547   */
1548  @Nullable
1549  public Double getElevation() {
1550    return elevation;
1551  }
1552
1553  public void setElevation(@Nullable Double elevation) {
1554    this.elevation = elevation;
1555  }
1556
1557  /**
1558   * Elevation accuracy is the uncertainty for the elevation in meters.
1559   * </br>
1560   * The elevation accuracy is calculated using the equation: (maximumElevationInMeters - minimumElevationInMeters) / 2
1561   */
1562  @Nullable
1563  public Double getElevationAccuracy() {
1564    return elevationAccuracy;
1565  }
1566
1567  public void setElevationAccuracy(@Nullable Double elevationAccuracy) {
1568    this.elevationAccuracy = elevationAccuracy;
1569  }
1570
1571  /**
1572   * Depth in meters below the surface. Complimentary to elevation, the depth can be 10 meters below the surface of a
1573   * lake in 1100m (=elevation).
1574   * </br>
1575   * The depth is calculated using the equation: (minimumDepthInMeters + maximumDepthInMeters) / 2.
1576   */
1577  @Nullable
1578  public Double getDepth() {
1579    return depth;
1580  }
1581
1582  public void setDepth(@Nullable Double depth) {
1583    this.depth = depth;
1584  }
1585
1586  /**
1587   * Depth accuracy is the uncertainty for the depth in meters.
1588   * </br>
1589   * The depth accuracy is calculated using the equation: (maximumDepthInMeters - minimumDepthInMeters) / 2
1590   */
1591  @Nullable
1592  public Double getDepthAccuracy() {
1593    return depthAccuracy;
1594  }
1595
1596  public void setDepthAccuracy(@Nullable Double depthAccuracy) {
1597    this.depthAccuracy = depthAccuracy;
1598  }
1599
1600  @Nullable
1601  public Continent getContinent() {
1602    return continent;
1603  }
1604
1605  public void setContinent(@Nullable Continent continent) {
1606    this.continent = continent;
1607  }
1608
1609  @Schema(
1610    description = "The 2-letter country code (as per ISO-3166-1) of the country, territory or area in which the " +
1611      "occurrence was recorded.",
1612    externalDocs = @ExternalDocumentation(
1613      description = "Darwin Core definition",
1614      url = "https://rs.tdwg.org/dwc/terms/countryCode"
1615    )
1616  )
1617  @Nullable
1618  @JsonProperty("countryCode")
1619  public Country getCountry() {
1620    return country;
1621  }
1622
1623  public void setCountry(@Nullable Country country) {
1624    this.country = country;
1625  }
1626
1627  @Nullable
1628  @JsonProperty("gbifRegion")
1629  public GbifRegion getGbifRegion() {
1630    return Optional.ofNullable(country).map(Country::getGbifRegion).orElse(null);
1631  }
1632
1633  private void setGbifRegion(String gbifRegion) {
1634    // ignore, setter only to avoid JSON being written into the fields map
1635  }
1636
1637  /**
1638   * Renders the country title as a JSON property country in addition to the ISO 3166 2 letter countryCode being
1639   * serialized by the regular country Java property.
1640   * Made private to use it only for JSON serialization and not within Java code.
1641   */
1642  @Schema(
1643    description = "The title (as per ISO-3166-1) of the country, territory or area in which the " +
1644      "occurrence was recorded.",
1645    externalDocs = @ExternalDocumentation(
1646      description = "Darwin Core definition",
1647      url = "https://rs.tdwg.org/dwc/terms/country"
1648    )
1649  )
1650  @Nullable
1651  @JsonProperty("country")
1652  private String getCountryTitle() {
1653    return country == null ? null : country.getTitle();
1654  }
1655
1656  private void setCountryTitle(String country) {
1657    // ignore, setter only to avoid JSON being written into the fields map
1658  }
1659
1660  @Nullable
1661  public String getStateProvince() {
1662    return stateProvince;
1663  }
1664
1665  public void setStateProvince(@Nullable String stateProvince) {
1666    this.stateProvince = stateProvince;
1667  }
1668
1669  @Nullable
1670  public String getWaterBody() {
1671    return waterBody;
1672  }
1673
1674  public void setWaterBody(@Nullable String waterBody) {
1675    this.waterBody = waterBody;
1676  }
1677
1678  /**
1679   * The distance in metres from a known centroid, e.g. a country centroid.
1680   */
1681  public Double getDistanceFromCentroidInMeters() {
1682    return distanceFromCentroidInMeters;
1683  }
1684
1685  public void setDistanceFromCentroidInMeters(Double distanceFromCentroidInMeters) {
1686    this.distanceFromCentroidInMeters = distanceFromCentroidInMeters;
1687  }
1688
1689  @Nullable
1690  public String getHigherGeography() {
1691    return higherGeography;
1692  }
1693
1694  public void setHigherGeography(String higherGeography) {
1695    this.higherGeography = higherGeography;
1696  }
1697
1698  @Nullable
1699  public String getGeoreferencedBy() {
1700    return georeferencedBy;
1701  }
1702
1703  public void setGeoreferencedBy(String georeferencedBy) {
1704    this.georeferencedBy = georeferencedBy;
1705  }
1706
1707  /**
1708   * The full year of the event date.
1709   *
1710   * @return the year of the event date
1711   */
1712  @Min(1500)
1713  @Max(2030)
1714  @Nullable
1715  public Integer getYear() {
1716    return year;
1717  }
1718
1719  public void setYear(@Nullable Integer year) {
1720    this.year = year;
1721  }
1722
1723  /**
1724   * The month of the year of the event date starting with zero for january following {@link Date}.
1725   *
1726   * @return the month of the event date
1727   */
1728  @Min(1)
1729  @Max(12)
1730  @Nullable
1731  public Integer getMonth() {
1732    return month;
1733  }
1734
1735  public void setMonth(@Nullable Integer month) {
1736    this.month = month;
1737  }
1738
1739  /**
1740   * The day of the month of the event date.
1741   *
1742   * @return the day of the event date
1743   */
1744  @Min(1)
1745  @Max(31)
1746  @Nullable
1747  public Integer getDay() {
1748    return day;
1749  }
1750
1751  public void setDay(@Nullable Integer day) {
1752    this.day = day;
1753  }
1754
1755  /**
1756   * The date the occurrence was recorded or collected.
1757   */
1758  @Nullable
1759  public IsoDateInterval getEventDate() {
1760    return eventDate == null ? null : new IsoDateInterval(eventDate.getFrom(), eventDate.getTo());
1761  }
1762
1763  public void setEventDate(@Nullable IsoDateInterval eventDate) {
1764    this.eventDate = eventDate == null ? null : new IsoDateInterval(eventDate.getFrom(), eventDate.getTo());
1765  }
1766
1767  /**
1768   * The earliest integer day of the year of the event.
1769   *
1770   * @return the earliest integer day of the event date
1771   */
1772  @Min(1)
1773  @Max(366)
1774  @Nullable
1775  public Integer getStartDayOfYear() {
1776    return startDayOfYear;
1777  }
1778
1779  public void setStartDayOfYear(@Nullable Integer startDayOfYear) {
1780    this.startDayOfYear = startDayOfYear;
1781  }
1782
1783  /**
1784   * The latest integer day of the year of the event.
1785   *
1786   * @return the latest integer day of the event date
1787   */
1788  @Min(1)
1789  @Max(366)
1790  @Nullable
1791  public Integer getEndDayOfYear() {
1792    return endDayOfYear;
1793  }
1794
1795  public void setEndDayOfYear(@Nullable Integer endDayOfYear) {
1796    this.endDayOfYear = endDayOfYear;
1797  }
1798
1799  @Nullable
1800  public String getTypeStatus() {
1801    return typeStatus;
1802  }
1803
1804  public void setTypeStatus(@Nullable String typeStatus) {
1805    this.typeStatus = typeStatus;
1806  }
1807
1808  /**
1809   * The scientific name the type status of this specimen applies to.
1810   */
1811  @Nullable
1812  public String getTypifiedName() {
1813    return typifiedName;
1814  }
1815
1816  public void setTypifiedName(@Nullable String typifiedName) {
1817    this.typifiedName = typifiedName;
1818  }
1819
1820  /**
1821   * A set of issues found for this occurrence.
1822   */
1823  @NotNull
1824  public Set<OccurrenceIssue> getIssues() {
1825    return issues;
1826  }
1827
1828  public void setIssues(Set<OccurrenceIssue> issues) {
1829    Objects.requireNonNull(issues, "Issues cannot be null");
1830    EnumSet<OccurrenceIssue> set = EnumSet.noneOf(OccurrenceIssue.class);
1831    set.addAll(issues);
1832    this.issues = set;
1833  }
1834
1835  public void addIssue(OccurrenceIssue issue) {
1836    Objects.requireNonNull(issue, "Issue needs to be specified");
1837    issues.add(issue);
1838  }
1839
1840  /**
1841   * The interpreted dc:modified from the verbatim source data.
1842   * Ideally indicating when a record was last modified in the source.
1843   */
1844  @Nullable
1845  public Date getModified() {
1846    return modified == null ? null : new Date(modified.getTime());
1847  }
1848
1849  public void setModified(@Nullable Date modified) {
1850    this.modified = modified == null ? null : new Date(modified.getTime());
1851  }
1852
1853  /**
1854   * The date this occurrence last went through the interpretation phase of the GBIF indexing.
1855   */
1856  @Nullable
1857  public Date getLastInterpreted() {
1858    return lastInterpreted == null ? null : new Date(lastInterpreted.getTime());
1859  }
1860
1861  public void setLastInterpreted(@Nullable Date lastInterpreted) {
1862    this.lastInterpreted = lastInterpreted == null ? null : new Date(lastInterpreted.getTime());
1863  }
1864
1865  /**
1866   * An external link to more details, the records "homepage".
1867   */
1868  @Nullable
1869  public URI getReferences() {
1870    return references;
1871  }
1872
1873  public void setReferences(URI references) {
1874    this.references = references;
1875  }
1876
1877  /**
1878   * A number or enumeration value for the quantity of organisms.
1879   */
1880  @Nullable
1881  public Double getOrganismQuantity() {
1882    return organismQuantity;
1883  }
1884
1885  public void setOrganismQuantity(@Nullable Double organismQuantity) {
1886    this.organismQuantity = organismQuantity;
1887  }
1888
1889  /**
1890   * The type of quantification system used for the quantity of organisms.
1891   */
1892  @Nullable
1893  public String getOrganismQuantityType() {
1894    return organismQuantityType;
1895  }
1896
1897  public void setOrganismQuantityType(@Nullable String organismQuantityType) {
1898    this.organismQuantityType = organismQuantityType;
1899  }
1900
1901  /**
1902   * The unit of measurement of the size (time duration, length, area, or volume) of a sample in a sampling event.
1903   */
1904  @Nullable
1905  public String getSampleSizeUnit() {
1906    return sampleSizeUnit;
1907  }
1908
1909  public void setSampleSizeUnit(@Nullable String sampleSizeUnit) {
1910    this.sampleSizeUnit = sampleSizeUnit;
1911  }
1912
1913  /**
1914   * A numeric value for a measurement of the size (time duration, length, area, or volume) of a sample in a sampling event.
1915   */
1916  @Nullable
1917  public Double getSampleSizeValue() {
1918    return sampleSizeValue;
1919  }
1920
1921  public void setSampleSizeValue(@Nullable Double sampleSizeValue) {
1922    this.sampleSizeValue = sampleSizeValue;
1923  }
1924
1925  /**
1926   * Calculated filed organismQuantity / sampleSizeValue, if the type is identical
1927   */
1928  @Nullable
1929  public Double getRelativeOrganismQuantity() {
1930    return relativeOrganismQuantity;
1931  }
1932
1933  public void setRelativeOrganismQuantity(@Nullable Double relativeOrganismQuantity) {
1934    this.relativeOrganismQuantity = relativeOrganismQuantity;
1935  }
1936
1937  /**
1938   * Flag occurrence when associatedSequences/extension exists
1939   */
1940  public boolean getIsSequenced() {
1941    return isSequenced;
1942  }
1943
1944  public void setIsSequenced(boolean isSequenced) {
1945    this.isSequenced = isSequenced;
1946  }
1947
1948  /**
1949   * A list (concatenated and separated) of identifiers (publication, global unique identifier, URI) of genetic
1950   * sequence information associated with the material entity.
1951   */
1952  @Nullable
1953  public String getAssociatedSequences() {
1954    return associatedSequences;
1955  }
1956
1957  public void setAssociatedSequences(String associatedSequences) {
1958    this.associatedSequences = associatedSequences;
1959  }
1960
1961  /**
1962   * Applied license to the occurrence record or dataset to which this record belongs to.
1963   */
1964  @NotNull
1965  public License getLicense() {
1966    return license;
1967  }
1968
1969  public void setLicense(License license) {
1970    this.license = license;
1971  }
1972
1973  @NotNull
1974  public List<Identifier> getIdentifiers() {
1975    return identifiers;
1976  }
1977
1978  public void setIdentifiers(List<Identifier> identifiers) {
1979    this.identifiers = identifiers;
1980  }
1981
1982  @NotNull
1983  public List<MediaObject> getMedia() {
1984    return media;
1985  }
1986
1987  public void setMedia(List<MediaObject> media) {
1988    this.media = media;
1989  }
1990
1991  @NotNull
1992  public List<MeasurementOrFact> getFacts() {
1993    return facts;
1994  }
1995
1996  public void setFacts(List<MeasurementOrFact> facts) {
1997    this.facts = facts;
1998  }
1999
2000  @NotNull
2001  public List<OccurrenceRelation> getRelations() {
2002    return relations;
2003  }
2004
2005  public void setRelations(List<OccurrenceRelation> relations) {
2006    this.relations = relations;
2007  }
2008
2009  @NotNull
2010  public List<AgentIdentifier> getRecordedByIds() {
2011    return recordedByIds;
2012  }
2013
2014  public void setRecordedByIds(List<AgentIdentifier> recordedByIds) {
2015    this.recordedByIds = recordedByIds;
2016  }
2017
2018  @NotNull
2019  public List<AgentIdentifier> getIdentifiedByIds() {
2020    return identifiedByIds;
2021  }
2022
2023  public void setIdentifiedByIds(List<AgentIdentifier> identifiedByIds) {
2024    this.identifiedByIds = identifiedByIds;
2025  }
2026
2027  @NotNull
2028  public Gadm getGadm() {
2029    return gadm;
2030  }
2031
2032  public void setGadm(Gadm gadm) {
2033    this.gadm = gadm;
2034  }
2035
2036  @Nullable
2037  @Experimental
2038  public String getInstitutionKey() {
2039    return institutionKey;
2040  }
2041
2042  public void setInstitutionKey(String institutionKey) {
2043    this.institutionKey = institutionKey;
2044  }
2045
2046  @Nullable
2047  @Experimental
2048  public String getCollectionKey() {
2049    return collectionKey;
2050  }
2051
2052  public void setCollectionKey(String collectionKey) {
2053    this.collectionKey = collectionKey;
2054  }
2055
2056  public boolean getIsInCluster() {
2057    return isInCluster;
2058  }
2059
2060  public void setIsInCluster(boolean isInCluster) {
2061    this.isInCluster = isInCluster;
2062  }
2063
2064  @Nullable
2065  public String getDegreeOfEstablishment() {
2066    return degreeOfEstablishment;
2067  }
2068
2069  public void setDegreeOfEstablishment(String degreeOfEstablishment) {
2070    this.degreeOfEstablishment = degreeOfEstablishment;
2071  }
2072
2073  @Nullable
2074  public String getPathway() {
2075    return pathway;
2076  }
2077
2078  public void setPathway(String pathway) {
2079    this.pathway = pathway;
2080  }
2081
2082  public String getDatasetID() {
2083    return datasetID;
2084  }
2085
2086  public void setDatasetID(String datasetID) {
2087    this.datasetID = datasetID;
2088  }
2089
2090  public String getDatasetName() {
2091    return datasetName;
2092  }
2093
2094  public void setDatasetName(String datasetName) {
2095    this.datasetName = datasetName;
2096  }
2097
2098  public String getOtherCatalogNumbers() {
2099    return otherCatalogNumbers;
2100  }
2101
2102  public void setOtherCatalogNumbers(String otherCatalogNumbers) {
2103    this.otherCatalogNumbers = otherCatalogNumbers;
2104  }
2105
2106  @Nullable
2107  public String getEarliestEonOrLowestEonothem() {
2108    return earliestEonOrLowestEonothem;
2109  }
2110
2111  public void setEarliestEonOrLowestEonothem(String earliestEonOrLowestEonothem) {
2112    this.earliestEonOrLowestEonothem = earliestEonOrLowestEonothem;
2113  }
2114
2115  @Nullable
2116  public String getLatestEonOrHighestEonothem() {
2117    return latestEonOrHighestEonothem;
2118  }
2119
2120  public void setLatestEonOrHighestEonothem(String latestEonOrHighestEonothem) {
2121    this.latestEonOrHighestEonothem = latestEonOrHighestEonothem;
2122  }
2123
2124  @Nullable
2125  public String getEarliestEraOrLowestErathem() {
2126    return earliestEraOrLowestErathem;
2127  }
2128
2129  public void setEarliestEraOrLowestErathem(String earliestEraOrLowestErathem) {
2130    this.earliestEraOrLowestErathem = earliestEraOrLowestErathem;
2131  }
2132
2133  @Nullable
2134  public String getLatestEraOrHighestErathem() {
2135    return latestEraOrHighestErathem;
2136  }
2137
2138  public void setLatestEraOrHighestErathem(String latestEraOrHighestErathem) {
2139    this.latestEraOrHighestErathem = latestEraOrHighestErathem;
2140  }
2141
2142  @Nullable
2143  public String getEarliestPeriodOrLowestSystem() {
2144    return earliestPeriodOrLowestSystem;
2145  }
2146
2147  public void setEarliestPeriodOrLowestSystem(String earliestPeriodOrLowestSystem) {
2148    this.earliestPeriodOrLowestSystem = earliestPeriodOrLowestSystem;
2149  }
2150
2151  @Nullable
2152  public String getLatestPeriodOrHighestSystem() {
2153    return latestPeriodOrHighestSystem;
2154  }
2155
2156  public void setLatestPeriodOrHighestSystem(String latestPeriodOrHighestSystem) {
2157    this.latestPeriodOrHighestSystem = latestPeriodOrHighestSystem;
2158  }
2159
2160  @Nullable
2161  public String getEarliestEpochOrLowestSeries() {
2162    return earliestEpochOrLowestSeries;
2163  }
2164
2165  public void setEarliestEpochOrLowestSeries(String earliestEpochOrLowestSeries) {
2166    this.earliestEpochOrLowestSeries = earliestEpochOrLowestSeries;
2167  }
2168
2169  @Nullable
2170  public String getLatestEpochOrHighestSeries() {
2171    return latestEpochOrHighestSeries;
2172  }
2173
2174  public void setLatestEpochOrHighestSeries(String latestEpochOrHighestSeries) {
2175    this.latestEpochOrHighestSeries = latestEpochOrHighestSeries;
2176  }
2177
2178  @Nullable
2179  public String getEarliestAgeOrLowestStage() {
2180    return earliestAgeOrLowestStage;
2181  }
2182
2183  public void setEarliestAgeOrLowestStage(String earliestAgeOrLowestStage) {
2184    this.earliestAgeOrLowestStage = earliestAgeOrLowestStage;
2185  }
2186
2187  @Nullable
2188  public String getLatestAgeOrHighestStage() {
2189    return latestAgeOrHighestStage;
2190  }
2191
2192  public void setLatestAgeOrHighestStage(String latestAgeOrHighestStage) {
2193    this.latestAgeOrHighestStage = latestAgeOrHighestStage;
2194  }
2195
2196  @Nullable
2197  public String getLowestBiostratigraphicZone() {
2198    return lowestBiostratigraphicZone;
2199  }
2200
2201  public void setLowestBiostratigraphicZone(String lowestBiostratigraphicZone) {
2202    this.lowestBiostratigraphicZone = lowestBiostratigraphicZone;
2203  }
2204
2205  @Nullable
2206  public String getHighestBiostratigraphicZone() {
2207    return highestBiostratigraphicZone;
2208  }
2209
2210  public void setHighestBiostratigraphicZone(String highestBiostratigraphicZone) {
2211    this.highestBiostratigraphicZone = highestBiostratigraphicZone;
2212  }
2213
2214  @Nullable
2215  public String getGroup() {
2216    return group;
2217  }
2218
2219  public void setGroup(String group) {
2220    this.group = group;
2221  }
2222
2223  @Nullable
2224  public String getFormation() {
2225    return formation;
2226  }
2227
2228  public void setFormation(String formation) {
2229    this.formation = formation;
2230  }
2231
2232  @Nullable
2233  public String getMember() {
2234    return member;
2235  }
2236
2237  public void setMember(String member) {
2238    this.member = member;
2239  }
2240
2241  @Nullable
2242  public String getBed() {
2243    return bed;
2244  }
2245
2246  public void setBed(String bed) {
2247    this.bed = bed;
2248  }
2249
2250  public String getRecordedBy() {
2251    return recordedBy;
2252  }
2253
2254  public void setRecordedBy(String recordedBy) {
2255    this.recordedBy = recordedBy;
2256  }
2257
2258  public String getIdentifiedBy() {
2259    return identifiedBy;
2260  }
2261
2262  public void setIdentifiedBy(String identifiedBy) {
2263    this.identifiedBy = identifiedBy;
2264  }
2265
2266  public String getPreparations() {
2267    return preparations;
2268  }
2269
2270  public void setPreparations(String preparations) {
2271    this.preparations = preparations;
2272  }
2273
2274  public String getSamplingProtocol() {
2275    return samplingProtocol;
2276  }
2277
2278  public void setSamplingProtocol(String samplingProtocol) {
2279    this.samplingProtocol = samplingProtocol;
2280  }
2281
2282  /**
2283   * Convenience method checking if any spatial validation rule has not passed.
2284   * Primarily used to indicate that the record should not be displayed on a map.
2285   */
2286  @JsonIgnore
2287  public boolean hasSpatialIssue() {
2288    for (OccurrenceIssue rule : OccurrenceIssue.GEOSPATIAL_RULES) {
2289      if (issues.contains(rule)) {
2290        return true;
2291      }
2292    }
2293    return false;
2294  }
2295
2296  /**
2297   * This private method is only for serialization via jackson and not exposed anywhere else!
2298   * It maps the verbatimField terms into properties with their simple name or qualified names for UnknownTerms.
2299   */
2300  @JsonAnyGetter
2301  private Map<String, String> jsonVerbatimFields() {
2302    Map<String, String> extendedProps = new HashMap<>();
2303    for (Map.Entry<Term, String> prop : getVerbatimFields().entrySet()) {
2304      Term t = prop.getKey();
2305      if (t instanceof UnknownTerm || PROPERTIES.contains(t.simpleName())) {
2306        extendedProps.put(t.qualifiedName(), prop.getValue());
2307      } else {
2308        // render all terms in controlled enumerations as simple names only - unless we have a property of that name already!
2309        extendedProps.put(t.simpleName(), prop.getValue());
2310      }
2311    }
2312    return extendedProps;
2313  }
2314}