Repository: focus-shift/jollyday
Pull request #739 (2025-01-28 12:47:09)

Add tests for jackson and jaxb
<!--

Thanks for contributing.
Please review the following notes before submitting you pull request.

Please look for other issues or pull requests which already work on this topic. Is somebody already on it? Do you need to synchronize?

# Security Vulnerabilities

🛑 STOP! 🛑 If your contribution fixes a security vulnerability, please do not submit it.
Instead, please write an E-Mail to to one of the maintainer with all the information
to recreate the security vulnerability.

# Describing Your Changes

If, having reviewed the notes above, you're ready to submit your pull request, please
provide a brief description of the proposed changes.

If they:
 🐞 fix a bug, please describe the broken behaviour and how the changes fix it.
    Please label with 'type: bug' and 'status: new'
    
 🎁 make an enhancement, please describe the new functionality and why you believe it's useful.
    Please label with 'type: enhancement' and 'status: new'
 
If your pull request relates to any existing issues,
please reference them by using the issue number prefixed with #.

-->


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739)


sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=focus-shift_jollyday&pullRequest=739&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=focus-shift_jollyday&pullRequest=739&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=focus-shift_jollyday&pullRequest=739&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=focus-shift_jollyday&pullRequest=739)



Patch:
diff --git a/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/MoveableHoliday.java b/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/MoveableHoliday.java
index 708c759a..b94e805b 100644
--- a/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/MoveableHoliday.java
+++ b/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/MoveableHoliday.java
@@ -37,4 +37,7 @@ public abstract class MoveableHoliday extends Holiday {
     return this.movingCondition;
   }
 
+  public void setMovingCondition(List<MovingCondition> movingCondition) {
+    this.movingCondition = movingCondition;
+  }
 }


Test patch:
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonChristianHolidayTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonChristianHolidayTest.java
new file mode 100644
index 00000000..cbfb8f9c
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonChristianHolidayTest.java
@@ -0,0 +1,69 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.Limited;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jackson.mapping.Fixed;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.RelativeToFixed;
+import de.focus_shift.jollyday.jackson.mapping.Weekday;
+import de.focus_shift.jollyday.jackson.mapping.When;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonChristianHolidayTest {
+
+  @Test
+  void ensureDateIsSetAndMappedCorrectly() {
+
+    final Fixed firstJanuary = new Fixed();
+    firstJanuary.setDay(1);
+    firstJanuary.setMonth(Month.JANUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setWeekday(Weekday.MONDAY);
+    relativeToFixed.setWhen(When.AFTER);
+    relativeToFixed.setDate(firstJanuary);
+    relativeToFixed.setEvery(HolidayCycleType.EVEN_YEARS);
+    relativeToFixed.setDescriptionPropertiesKey("description");
+    relativeToFixed.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    relativeToFixed.setValidFrom(2000);
+    relativeToFixed.setValidTo(2001);
+    final JacksonRelativeToFixed jacksonRelativeToFixed = new JacksonRelativeToFixed(relativeToFixed);
+
+    assertThat(jacksonRelativeToFixed.date().day()).isEqualTo(new JacksonFixed(firstJanuary).day());
+    assertThat(jacksonRelativeToFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonRelativeToFixed.when()).isEqualTo(Relation.AFTER);
+    assertThat(jacksonRelativeToFixed.cycle()).isEqualTo(Limited.YearCycle.EVEN_YEARS);
+    assertThat(jacksonRelativeToFixed.descriptionPropertiesKey()).isEqualTo("description");
+    assertThat(jacksonRelativeToFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonRelativeToFixed.validFrom()).isEqualTo(Year.of(2000));
+    assertThat(jacksonRelativeToFixed.validTo()).isEqualTo(Year.of(2001));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+
+    final Fixed firstJanuary = new Fixed();
+    firstJanuary.setDay(1);
+    firstJanuary.setMonth(Month.JANUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setDate(firstJanuary);
+    final JacksonRelativeToFixed jacksonRelativeToFixed = new JacksonRelativeToFixed(relativeToFixed);
+
+    assertThat(jacksonRelativeToFixed.date().day()).isEqualTo(new JacksonFixed(firstJanuary).day());
+    assertThat(jacksonRelativeToFixed.weekday()).isNull();
+    assertThat(jacksonRelativeToFixed.when()).isNull();
+    assertThat(jacksonRelativeToFixed.cycle()).isEqualTo(Limited.YearCycle.EVERY_YEAR);
+    assertThat(jacksonRelativeToFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonRelativeToFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonRelativeToFixed.validFrom()).isNull();
+    assertThat(jacksonRelativeToFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonConfigurationTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonConfigurationTest.java
new file mode 100644
index 00000000..c6b31a5a
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonConfigurationTest.java
@@ -0,0 +1,36 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.jackson.mapping.Configuration;
+import de.focus_shift.jollyday.jackson.mapping.Holidays;
+import de.focus_shift.jollyday.jackson.mapping.Sources;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonConfigurationTest {
+
+  @Test
+  void ensuresCorrectMapping() {
+
+    final Configuration configuration = new Configuration();
+    configuration.setDescription("description");
+    configuration.setHierarchy("hierarchy");
+
+    final Configuration subConfiguration = new Configuration();
+    subConfiguration.setHierarchy("subHierarchy");
+    configuration.getSubConfigurations().add(subConfiguration);
+
+    final Holidays holidays = new Holidays();
+    configuration.setHolidays(holidays);
+
+    final Sources sources = new Sources();
+    configuration.setSources(sources);
+
+    final JacksonConfiguration sut = new JacksonConfiguration(configuration);
+    assertThat(sut.holidays()).isNotNull();
+    assertThat(sut.subConfigurations().findFirst())
+      .hasValueSatisfying(subConf -> assertThat(subConf.hierarchy()).isEqualTo("subHierarchy"));
+    assertThat(sut.hierarchy()).isEqualTo("hierarchy");
+    assertThat(sut.description()).isEqualTo("description");
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonEthiopianOrthodoxHolidayTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonEthiopianOrthodoxHolidayTest.java
new file mode 100644
index 00000000..bae6c0fb
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonEthiopianOrthodoxHolidayTest.java
@@ -0,0 +1,48 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.EthiopianOrthodoxHoliday.EthiopianOrthodoxHolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jackson.mapping.EthiopianOrthodoxHoliday;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayType;
+import org.junit.jupiter.api.Test;
+
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonEthiopianOrthodoxHolidayTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final EthiopianOrthodoxHoliday ethiopianOrthodoxHoliday = new EthiopianOrthodoxHoliday();
+    ethiopianOrthodoxHoliday.setType(de.focus_shift.jollyday.jackson.mapping.EthiopianOrthodoxHolidayType.TIMKAT);
+    ethiopianOrthodoxHoliday.setEvery(HolidayCycleType.ODD_YEARS);
+    ethiopianOrthodoxHoliday.setDescriptionPropertiesKey("ethiopian.description");
+    ethiopianOrthodoxHoliday.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    ethiopianOrthodoxHoliday.setValidFrom(2010);
+    ethiopianOrthodoxHoliday.setValidTo(2020);
+
+    final JacksonEthiopianOrthodoxHoliday jacksonEthiopianOrthodoxHoliday = new JacksonEthiopianOrthodoxHoliday(ethiopianOrthodoxHoliday);
+    assertThat(jacksonEthiopianOrthodoxHoliday.type()).isEqualTo(EthiopianOrthodoxHolidayType.TIMKAT);
+    assertThat(jacksonEthiopianOrthodoxHoliday.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonEthiopianOrthodoxHoliday.descriptionPropertiesKey()).isEqualTo("ethiopian.description");
+    assertThat(jacksonEthiopianOrthodoxHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonEthiopianOrthodoxHoliday.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jacksonEthiopianOrthodoxHoliday.validTo()).isEqualTo(Year.of(2020));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final EthiopianOrthodoxHoliday ethiopianOrthodoxHoliday = new EthiopianOrthodoxHoliday();
+    ethiopianOrthodoxHoliday.setType(de.focus_shift.jollyday.jackson.mapping.EthiopianOrthodoxHolidayType.TIMKAT);
+
+    final JacksonEthiopianOrthodoxHoliday jacksonEthiopianOrthodoxHoliday = new JacksonEthiopianOrthodoxHoliday(ethiopianOrthodoxHoliday);
+    assertThat(jacksonEthiopianOrthodoxHoliday.type()).isEqualTo(EthiopianOrthodoxHolidayType.TIMKAT);
+    assertThat(jacksonEthiopianOrthodoxHoliday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonEthiopianOrthodoxHoliday.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonEthiopianOrthodoxHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonEthiopianOrthodoxHoliday.validFrom()).isNull();
+    assertThat(jacksonEthiopianOrthodoxHoliday.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedTest.java
new file mode 100644
index 00000000..63db3a7b
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedTest.java
@@ -0,0 +1,61 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jackson.mapping.Fixed;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.MovingCondition;
+import org.junit.jupiter.api.Test;
+
+import java.time.MonthDay;
+import java.time.Year;
+import java.util.Collections;
+import java.util.List;
+
+import static java.time.Month.DECEMBER;
+import static java.time.Month.JANUARY;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(25);
+    fixed.setMonth(Month.DECEMBER);
+    fixed.setEvery(HolidayCycleType.ODD_YEARS);
+    fixed.setDescriptionPropertiesKey("fixed.description");
+    fixed.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    fixed.setValidFrom(2010);
+    fixed.setValidTo(2020);
+    final MovingCondition movingCondition = new MovingCondition();
+    fixed.setMovingCondition(List.of(movingCondition));
+
+    final JacksonFixed jacksonFixed = new JacksonFixed(fixed);
+    assertThat(jacksonFixed.day()).isEqualTo(MonthDay.of(DECEMBER, 25));
+    assertThat(jacksonFixed.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonFixed.descriptionPropertiesKey()).isEqualTo("fixed.description");
+    assertThat(jacksonFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonFixed.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jacksonFixed.validTo()).isEqualTo(Year.of(2020));
+    assertThat(jacksonFixed.conditions()).hasSize(1);
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(1);
+    fixed.setMonth(Month.JANUARY);
+    fixed.setMovingCondition(Collections.emptyList());
+
+    final JacksonFixed jacksonFixed = new JacksonFixed(fixed);
+    assertThat(jacksonFixed.day()).isEqualTo(MonthDay.of(JANUARY, 1));
+    assertThat(jacksonFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonFixed.validFrom()).isNull();
+    assertThat(jacksonFixed.validTo()).isNull();
+    assertThat(jacksonFixed.conditions()).isEmpty();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayBetweenFixedTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayBetweenFixedTest.java
new file mode 100644
index 00000000..faa45394
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayBetweenFixedTest.java
@@ -0,0 +1,78 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jackson.mapping.Fixed;
+import de.focus_shift.jollyday.jackson.mapping.FixedWeekdayBetweenFixed;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.Weekday;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.MonthDay;
+import java.time.Year;
+
+import static de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY;
+import static java.time.Month.JANUARY;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonFixedWeekdayBetweenFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed from = new Fixed();
+    from.setDay(1);
+    from.setMonth(Month.JANUARY);
+
+    final Fixed to = new Fixed();
+    to.setDay(10);
+    to.setMonth(Month.JANUARY);
+
+    final FixedWeekdayBetweenFixed fixedWeekdayBetweenFixed = new FixedWeekdayBetweenFixed();
+    fixedWeekdayBetweenFixed.setFrom(from);
+    fixedWeekdayBetweenFixed.setTo(to);
+    fixedWeekdayBetweenFixed.setWeekday(Weekday.MONDAY);
+    fixedWeekdayBetweenFixed.setEvery(HolidayCycleType.ODD_YEARS);
+    fixedWeekdayBetweenFixed.setDescriptionPropertiesKey("between.description");
+    fixedWeekdayBetweenFixed.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    fixedWeekdayBetweenFixed.setValidFrom(2010);
+    fixedWeekdayBetweenFixed.setValidTo(2020);
+
+    final JacksonFixedWeekdayBetweenFixed jacksonFixedWeekdayBetweenFixed = new JacksonFixedWeekdayBetweenFixed(fixedWeekdayBetweenFixed);
+    assertThat(jacksonFixedWeekdayBetweenFixed.from().day()).isEqualTo(MonthDay.of(JANUARY, 1));
+    assertThat(jacksonFixedWeekdayBetweenFixed.to().day()).isEqualTo(MonthDay.of(JANUARY, 10));
+    assertThat(jacksonFixedWeekdayBetweenFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonFixedWeekdayBetweenFixed.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonFixedWeekdayBetweenFixed.descriptionPropertiesKey()).isEqualTo("between.description");
+    assertThat(jacksonFixedWeekdayBetweenFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonFixedWeekdayBetweenFixed.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jacksonFixedWeekdayBetweenFixed.validTo()).isEqualTo(Year.of(2020));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed from = new Fixed();
+    from.setDay(1);
+    from.setMonth(Month.JANUARY);
+
+    final Fixed to = new Fixed();
+    to.setDay(10);
+    to.setMonth(Month.JANUARY);
+
+    final FixedWeekdayBetweenFixed fixedWeekdayBetweenFixed = new FixedWeekdayBetweenFixed();
+    fixedWeekdayBetweenFixed.setFrom(from);
+    fixedWeekdayBetweenFixed.setTo(to);
+    fixedWeekdayBetweenFixed.setWeekday(Weekday.MONDAY);
+
+    final JacksonFixedWeekdayBetweenFixed jacksonFixedWeekdayBetweenFixed = new JacksonFixedWeekdayBetweenFixed(fixedWeekdayBetweenFixed);
+    assertThat(jacksonFixedWeekdayBetweenFixed.from().day()).isEqualTo(MonthDay.of(JANUARY, 1));
+    assertThat(jacksonFixedWeekdayBetweenFixed.to().day()).isEqualTo(MonthDay.of(JANUARY, 10));
+    assertThat(jacksonFixedWeekdayBetweenFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonFixedWeekdayBetweenFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonFixedWeekdayBetweenFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonFixedWeekdayBetweenFixed.holidayType()).isEqualTo(PUBLIC_HOLIDAY);
+    assertThat(jacksonFixedWeekdayBetweenFixed.validFrom()).isNull();
+    assertThat(jacksonFixedWeekdayBetweenFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayInMonthTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayInMonthTest.java
new file mode 100644
index 00000000..9b5c6c8c
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayInMonthTest.java
@@ -0,0 +1,60 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Occurrence;
+import de.focus_shift.jollyday.jackson.mapping.FixedWeekdayInMonth;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.Weekday;
+import de.focus_shift.jollyday.jackson.mapping.Which;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonFixedWeekdayInMonthTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final FixedWeekdayInMonth fixedWeekdayInMonth = new FixedWeekdayInMonth();
+    fixedWeekdayInMonth.setWeekday(Weekday.MONDAY);
+    fixedWeekdayInMonth.setMonth(Month.MARCH);
+    fixedWeekdayInMonth.setWhich(Which.FIRST);
+    fixedWeekdayInMonth.setEvery(HolidayCycleType.ODD_YEARS);
+    fixedWeekdayInMonth.setDescriptionPropertiesKey("weekdayinmonth.description");
+    fixedWeekdayInMonth.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    fixedWeekdayInMonth.setValidFrom(2012);
+    fixedWeekdayInMonth.setValidTo(2022);
+
+    final JacksonFixedWeekdayInMonth jacksonFixedWeekdayInMonth = new JacksonFixedWeekdayInMonth(fixedWeekdayInMonth);
+    assertThat(jacksonFixedWeekdayInMonth.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonFixedWeekdayInMonth.month()).isEqualTo(java.time.Month.MARCH);
+    assertThat(jacksonFixedWeekdayInMonth.which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jacksonFixedWeekdayInMonth.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonFixedWeekdayInMonth.descriptionPropertiesKey()).isEqualTo("weekdayinmonth.description");
+    assertThat(jacksonFixedWeekdayInMonth.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonFixedWeekdayInMonth.validFrom()).isEqualTo(Year.of(2012));
+    assertThat(jacksonFixedWeekdayInMonth.validTo()).isEqualTo(Year.of(2022));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final FixedWeekdayInMonth mapping = new FixedWeekdayInMonth();
+    mapping.setWeekday(Weekday.FRIDAY);
+    mapping.setMonth(Month.JUNE);
+    mapping.setWhich(Which.LAST);
+
+    final JacksonFixedWeekdayInMonth holiday = new JacksonFixedWeekdayInMonth(mapping);
+    assertThat(holiday.weekday()).isEqualTo(DayOfWeek.FRIDAY);
+    assertThat(holiday.month()).isEqualTo(java.time.Month.JUNE);
+    assertThat(holiday.which()).isEqualTo(Occurrence.LAST);
+    assertThat(holiday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(holiday.descriptionPropertiesKey()).isNull();
+    assertThat(holiday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(holiday.validFrom()).isNull();
+    assertThat(holiday.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayRelativeToFixedTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayRelativeToFixedTest.java
new file mode 100644
index 00000000..13fa8491
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonFixedWeekdayRelativeToFixedTest.java
@@ -0,0 +1,77 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Occurrence;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jackson.mapping.Fixed;
+import de.focus_shift.jollyday.jackson.mapping.FixedWeekdayRelativeToFixed;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.Weekday;
+import de.focus_shift.jollyday.jackson.mapping.When;
+import de.focus_shift.jollyday.jackson.mapping.Which;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.MonthDay;
+import java.time.Year;
+
+import static de.focus_shift.jollyday.jackson.mapping.HolidayType.BANK_HOLIDAY;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonFixedWeekdayRelativeToFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(15);
+    fixed.setMonth(Month.APRIL);
+
+    final FixedWeekdayRelativeToFixed fixedWeekdayRelativeToFixed = new FixedWeekdayRelativeToFixed();
+    fixedWeekdayRelativeToFixed.setDay(fixed);
+    fixedWeekdayRelativeToFixed.setWeekday(Weekday.THURSDAY);
+    fixedWeekdayRelativeToFixed.setWhen(When.BEFORE);
+    fixedWeekdayRelativeToFixed.setWhich(Which.SECOND);
+    fixedWeekdayRelativeToFixed.setEvery(HolidayCycleType.EVEN_YEARS);
+    fixedWeekdayRelativeToFixed.setDescriptionPropertiesKey("relative.description");
+    fixedWeekdayRelativeToFixed.setLocalizedType(BANK_HOLIDAY);
+    fixedWeekdayRelativeToFixed.setValidFrom(2011);
+    fixedWeekdayRelativeToFixed.setValidTo(2021);
+
+    final JacksonFixedWeekdayRelativeToFixed jacksonFixedWeekdayRelativeToFixed = new JacksonFixedWeekdayRelativeToFixed(fixedWeekdayRelativeToFixed);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.day().day()).isEqualTo(MonthDay.of(java.time.Month.APRIL, 15));
+    assertThat(jacksonFixedWeekdayRelativeToFixed.weekday()).isEqualTo(DayOfWeek.THURSDAY);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.when()).isEqualTo(Relation.BEFORE);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.which()).isEqualTo(Occurrence.SECOND);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.cycle()).isEqualTo(YearCycle.EVEN_YEARS);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.descriptionPropertiesKey()).isEqualTo("relative.description");
+    assertThat(jacksonFixedWeekdayRelativeToFixed.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.validFrom()).isEqualTo(Year.of(2011));
+    assertThat(jacksonFixedWeekdayRelativeToFixed.validTo()).isEqualTo(Year.of(2021));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(5);
+    fixed.setMonth(Month.MAY);
+
+    final FixedWeekdayRelativeToFixed fixedWeekdayRelativeToFixed = new FixedWeekdayRelativeToFixed();
+    fixedWeekdayRelativeToFixed.setDay(fixed);
+    fixedWeekdayRelativeToFixed.setWeekday(Weekday.MONDAY);
+    fixedWeekdayRelativeToFixed.setWhen(When.AFTER);
+    fixedWeekdayRelativeToFixed.setWhich(Which.FIRST);
+
+    final JacksonFixedWeekdayRelativeToFixed jacksonFixedWeekdayRelativeToFixed = new JacksonFixedWeekdayRelativeToFixed(fixedWeekdayRelativeToFixed);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.day().day()).isEqualTo(MonthDay.of(java.time.Month.MAY, 5));
+    assertThat(jacksonFixedWeekdayRelativeToFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.when()).isEqualTo(Relation.AFTER);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonFixedWeekdayRelativeToFixed.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonFixedWeekdayRelativeToFixed.validFrom()).isNull();
+    assertThat(jacksonFixedWeekdayRelativeToFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonIslamicHolidayTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonIslamicHolidayTest.java
new file mode 100644
index 00000000..61f3d170
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonIslamicHolidayTest.java
@@ -0,0 +1,56 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.IslamicHoliday.IslamicHolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayType;
+import de.focus_shift.jollyday.jackson.mapping.IslamicHoliday;
+import de.focus_shift.jollyday.jackson.mapping.MovingCondition;
+import org.junit.jupiter.api.Test;
+
+import java.time.Year;
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonIslamicHolidayTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final IslamicHoliday islamicHoliday = new IslamicHoliday();
+    islamicHoliday.setType(de.focus_shift.jollyday.jackson.mapping.IslamicHolidayType.ID_UL_ADHA);
+    islamicHoliday.setEvery(HolidayCycleType.ODD_YEARS);
+    islamicHoliday.setDescriptionPropertiesKey("islamic.description");
+    islamicHoliday.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    islamicHoliday.setValidFrom(2015);
+    islamicHoliday.setValidTo(2025);
+
+    final MovingCondition movingCondition = new MovingCondition();
+    islamicHoliday.setMovingCondition(Collections.singletonList(movingCondition));
+
+    final JacksonIslamicHoliday jacksonIslamicHoliday = new JacksonIslamicHoliday(islamicHoliday);
+    assertThat(jacksonIslamicHoliday.type()).isEqualTo(IslamicHolidayType.ID_UL_ADHA);
+    assertThat(jacksonIslamicHoliday.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonIslamicHoliday.descriptionPropertiesKey()).isEqualTo("islamic.description");
+    assertThat(jacksonIslamicHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonIslamicHoliday.validFrom()).isEqualTo(Year.of(2015));
+    assertThat(jacksonIslamicHoliday.validTo()).isEqualTo(Year.of(2025));
+    assertThat(jacksonIslamicHoliday.conditions()).hasSize(1);
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final IslamicHoliday islamicHoliday = new IslamicHoliday();
+    islamicHoliday.setType(de.focus_shift.jollyday.jackson.mapping.IslamicHolidayType.ID_UL_ADHA);
+    islamicHoliday.setMovingCondition(Collections.emptyList());
+
+    final JacksonIslamicHoliday jacksonIslamicHoliday = new JacksonIslamicHoliday(islamicHoliday);
+    assertThat(jacksonIslamicHoliday.type()).isEqualTo(IslamicHolidayType.ID_UL_ADHA);
+    assertThat(jacksonIslamicHoliday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonIslamicHoliday.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonIslamicHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonIslamicHoliday.validFrom()).isNull();
+    assertThat(jacksonIslamicHoliday.validTo()).isNull();
+    assertThat(jacksonIslamicHoliday.conditions()).isEmpty();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonMovingConditionTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonMovingConditionTest.java
new file mode 100644
index 00000000..243ba05b
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonMovingConditionTest.java
@@ -0,0 +1,37 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.spi.Movable;
+import de.focus_shift.jollyday.jackson.mapping.MovingCondition;
+import de.focus_shift.jollyday.jackson.mapping.Weekday;
+import de.focus_shift.jollyday.jackson.mapping.With;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class JacksonMovingConditionTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final MovingCondition movingCondition = new MovingCondition();
+    movingCondition.setSubstitute(Weekday.SATURDAY);
+    movingCondition.setWith(With.NEXT);
+    movingCondition.setWeekday(Weekday.MONDAY);
+
+    final JacksonMovingCondition jacksonMovingCondition = new JacksonMovingCondition(movingCondition);
+    assertThat(jacksonMovingCondition.substitute()).isEqualTo(DayOfWeek.SATURDAY);
+    assertThat(jacksonMovingCondition.with()).isEqualTo(Movable.MovingCondition.With.NEXT);
+    assertThat(jacksonMovingCondition.weekday()).isEqualTo(DayOfWeek.MONDAY);
+  }
+
+  @Test
+  void ensureNullPointerOnUnsetValues() {
+    final MovingCondition movingCondition = new MovingCondition();
+    final JacksonMovingCondition jacksonMovingCondition = new JacksonMovingCondition(movingCondition);
+    assertThrows(NullPointerException.class, jacksonMovingCondition::substitute);
+    assertThrows(NullPointerException.class, jacksonMovingCondition::with);
+    assertThrows(NullPointerException.class, jacksonMovingCondition::weekday);
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToEasterSundayTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToEasterSundayTest.java
new file mode 100644
index 00000000..1d702b8c
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToEasterSundayTest.java
@@ -0,0 +1,54 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jackson.mapping.ChronologyType;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.RelativeToEasterSunday;
+import org.junit.jupiter.api.Test;
+import org.threeten.extra.Days;
+import org.threeten.extra.chrono.JulianChronology;
+
+import java.time.Year;
+import java.time.chrono.IsoChronology;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonRelativeToEasterSundayTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final RelativeToEasterSunday relativeToEasterSunday = new RelativeToEasterSunday();
+    relativeToEasterSunday.setDays(10);
+    relativeToEasterSunday.setChronology(ChronologyType.JULIAN);
+    relativeToEasterSunday.setEvery(HolidayCycleType.ODD_YEARS);
+    relativeToEasterSunday.setDescriptionPropertiesKey("easter.description");
+    relativeToEasterSunday.setLocalizedType(de.focus_shift.jollyday.jackson.mapping.HolidayType.BANK_HOLIDAY);
+    relativeToEasterSunday.setValidFrom(2015);
+    relativeToEasterSunday.setValidTo(2025);
+
+    final JacksonRelativeToEasterSunday jacksonRelativeToEasterSunday = new JacksonRelativeToEasterSunday(relativeToEasterSunday);
+    assertThat(jacksonRelativeToEasterSunday.days()).isEqualTo(Days.of(10));
+    assertThat(jacksonRelativeToEasterSunday.chronology()).isEqualTo(JulianChronology.INSTANCE);
+    assertThat(jacksonRelativeToEasterSunday.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonRelativeToEasterSunday.descriptionPropertiesKey()).isEqualTo("easter.description");
+    assertThat(jacksonRelativeToEasterSunday.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonRelativeToEasterSunday.validFrom()).isEqualTo(Year.of(2015));
+    assertThat(jacksonRelativeToEasterSunday.validTo()).isEqualTo(Year.of(2025));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final RelativeToEasterSunday relativeToEasterSunday = new RelativeToEasterSunday();
+    relativeToEasterSunday.setDays(-2);
+
+    final JacksonRelativeToEasterSunday jacksonRelativeToEasterSunday = new JacksonRelativeToEasterSunday(relativeToEasterSunday);
+    assertThat(jacksonRelativeToEasterSunday.days()).isEqualTo(Days.of(-2));
+    assertThat(jacksonRelativeToEasterSunday.chronology()).isEqualTo(IsoChronology.INSTANCE);
+    assertThat(jacksonRelativeToEasterSunday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonRelativeToEasterSunday.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonRelativeToEasterSunday.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonRelativeToEasterSunday.validFrom()).isNull();
+    assertThat(jacksonRelativeToEasterSunday.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToFixedTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToFixedTest.java
new file mode 100644
index 00000000..bb0e56f5
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToFixedTest.java
@@ -0,0 +1,67 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jackson.mapping.Fixed;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.RelativeToFixed;
+import de.focus_shift.jollyday.jackson.mapping.When;
+import org.junit.jupiter.api.Test;
+import org.threeten.extra.Days;
+
+import java.time.MonthDay;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonRelativeToFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(1);
+    fixed.setMonth(Month.JANUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setDate(fixed);
+    relativeToFixed.setDays(3);
+    relativeToFixed.setWhen(When.AFTER);
+    relativeToFixed.setEvery(HolidayCycleType.ODD_YEARS);
+    relativeToFixed.setDescriptionPropertiesKey("relative.fixed.description");
+    relativeToFixed.setLocalizedType(de.focus_shift.jollyday.jackson.mapping.HolidayType.BANK_HOLIDAY);
+    relativeToFixed.setValidFrom(2000);
+    relativeToFixed.setValidTo(2020);
+
+    final JacksonRelativeToFixed jacksonRelativeToFixed = new JacksonRelativeToFixed(relativeToFixed);
+    assertThat(jacksonRelativeToFixed.date().day()).isEqualTo(MonthDay.of(java.time.Month.JANUARY, 1));
+    assertThat(jacksonRelativeToFixed.days()).isEqualTo(Days.of(3));
+    assertThat(jacksonRelativeToFixed.when()).isEqualTo(Relation.AFTER);
+    assertThat(jacksonRelativeToFixed.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jacksonRelativeToFixed.descriptionPropertiesKey()).isEqualTo("relative.fixed.description");
+    assertThat(jacksonRelativeToFixed.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonRelativeToFixed.validFrom()).isEqualTo(Year.of(2000));
+    assertThat(jacksonRelativeToFixed.validTo()).isEqualTo(Year.of(2020));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(10);
+    fixed.setMonth(Month.FEBRUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setDate(fixed);
+
+    final JacksonRelativeToFixed jacksonRelativeToFixed = new JacksonRelativeToFixed(relativeToFixed);
+    assertThat(jacksonRelativeToFixed.date().day()).isEqualTo(MonthDay.of(java.time.Month.FEBRUARY, 10));
+    assertThat(jacksonRelativeToFixed.days()).isNull();
+    assertThat(jacksonRelativeToFixed.when()).isNull();
+    assertThat(jacksonRelativeToFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jacksonRelativeToFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonRelativeToFixed.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonRelativeToFixed.validFrom()).isNull();
+    assertThat(jacksonRelativeToFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToWeekdayInMonthTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToWeekdayInMonthTest.java
new file mode 100644
index 00000000..37d9b5c9
--- /dev/null
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonRelativeToWeekdayInMonthTest.java
@@ -0,0 +1,77 @@
+package de.focus_shift.jollyday.jackson;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Occurrence;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jackson.mapping.FixedWeekdayInMonth;
+import de.focus_shift.jollyday.jackson.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jackson.mapping.Month;
+import de.focus_shift.jollyday.jackson.mapping.RelativeToWeekdayInMonth;
+import de.focus_shift.jollyday.jackson.mapping.Weekday;
+import de.focus_shift.jollyday.jackson.mapping.When;
+import de.focus_shift.jollyday.jackson.mapping.Which;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JacksonRelativeToWeekdayInMonthTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final FixedWeekdayInMonth fixedWeekdayInMonth = new FixedWeekdayInMonth();
+    fixedWeekdayInMonth.setMonth(Month.MARCH);
+    fixedWeekdayInMonth.setWhich(Which.FIRST);
+    fixedWeekdayInMonth.setWeekday(Weekday.FRIDAY);
+
+    final RelativeToWeekdayInMonth relativeToWeekdayInMonth = new RelativeToWeekdayInMonth();
+    relativeToWeekdayInMonth.setFixedWeekday(fixedWeekdayInMonth);
+    relativeToWeekdayInMonth.setWeekday(Weekday.MONDAY);
+    relativeToWeekdayInMonth.setWhen(When.BEFORE);
+    relativeToWeekdayInMonth.setDescriptionPropertiesKey("weekdayinmonth.description");
+    relativeToWeekdayInMonth.setLocalizedType(de.focus_shift.jollyday.jackson.mapping.HolidayType.BANK_HOLIDAY);
+    relativeToWeekdayInMonth.setValidFrom(2010);
+    relativeToWeekdayInMonth.setValidTo(2020);
+    relativeToWeekdayInMonth.setEvery(HolidayCycleType.ODD_YEARS);
+
+    final JacksonRelativeToWeekdayInMonth jacksonRelativeToWeekdayInMonth = new JacksonRelativeToWeekdayInMonth(relativeToWeekdayInMonth);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekdayInMonth().which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekdayInMonth().weekday()).isEqualTo(DayOfWeek.FRIDAY);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekdayInMonth().month()).isEqualTo(java.time.Month.MARCH);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonRelativeToWeekdayInMonth.when()).isEqualTo(Relation.BEFORE);
+    assertThat(jacksonRelativeToWeekdayInMonth.descriptionPropertiesKey()).isEqualTo("weekdayinmonth.description");
+    assertThat(jacksonRelativeToWeekdayInMonth.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jacksonRelativeToWeekdayInMonth.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jacksonRelativeToWeekdayInMonth.validTo()).isEqualTo(Year.of(2020));
+    assertThat(jacksonRelativeToWeekdayInMonth.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final FixedWeekdayInMonth fixedWeekdayInMonth = new FixedWeekdayInMonth();
+    fixedWeekdayInMonth.setMonth(Month.APRIL);
+    fixedWeekdayInMonth.setWhich(Which.FIRST);
+    fixedWeekdayInMonth.setWeekday(Weekday.SUNDAY);
+
+    final RelativeToWeekdayInMonth relativeToWeekdayInMonth = new RelativeToWeekdayInMonth();
+    relativeToWeekdayInMonth.setFixedWeekday(fixedWeekdayInMonth);
+    relativeToWeekdayInMonth.setWeekday(Weekday.MONDAY);
+    relativeToWeekdayInMonth.setWhen(When.AFTER);
+
+    final JacksonRelativeToWeekdayInMonth jacksonRelativeToWeekdayInMonth = new JacksonRelativeToWeekdayInMonth(relativeToWeekdayInMonth);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekdayInMonth().which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekdayInMonth().weekday()).isEqualTo(DayOfWeek.SUNDAY);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekdayInMonth().month()).isEqualTo(java.time.Month.APRIL);
+    assertThat(jacksonRelativeToWeekdayInMonth.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jacksonRelativeToWeekdayInMonth.when()).isEqualTo(Relation.AFTER);
+    assertThat(jacksonRelativeToWeekdayInMonth.descriptionPropertiesKey()).isNull();
+    assertThat(jacksonRelativeToWeekdayInMonth.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jacksonRelativeToWeekdayInMonth.validFrom()).isNull();
+    assertThat(jacksonRelativeToWeekdayInMonth.validTo()).isNull();
+    assertThat(jacksonRelativeToWeekdayInMonth.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+  }
+}
diff --git a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/test/JacksonXMLMapperTest.java b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonXMLMapperTest.java
similarity index 88%
rename from jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/test/JacksonXMLMapperTest.java
rename to jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonXMLMapperTest.java
index a5ccd710..2a1b5d1a 100644
--- a/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/test/JacksonXMLMapperTest.java
+++ b/jollyday-jackson/src/test/java/de/focus_shift/jollyday/jackson/JacksonXMLMapperTest.java
@@ -1,6 +1,5 @@
-package de.focus_shift.jollyday.jackson.test;
+package de.focus_shift.jollyday.jackson;
 
-import de.focus_shift.jollyday.jackson.JacksonXMLMapper;
 import de.focus_shift.jollyday.jackson.mapping.Configuration;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
diff --git a/jollyday-jackson/src/test/java/module-info.java b/jollyday-jackson/src/test/java/module-info.java
deleted file mode 100644
index 7fd71db9..00000000
--- a/jollyday-jackson/src/test/java/module-info.java
+++ /dev/null
@@ -1,13 +0,0 @@
-module de.focus_shift.jollyday.jackson.test {
-
-  opens de.focus_shift.jollyday.jackson.test to
-    org.junit.platform.commons;
-
-  requires com.fasterxml.jackson.databind;
-  requires com.fasterxml.jackson.dataformat.xml;
-  requires de.focus_shift.jollyday.core;
-  requires de.focus_shift.jollyday.jackson;
-  requires org.assertj.core;
-  requires org.junit.jupiter.api;
-  requires org.junit.jupiter.params;
-}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbChristianHolidayTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbChristianHolidayTest.java
new file mode 100644
index 00000000..57957daf
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbChristianHolidayTest.java
@@ -0,0 +1,69 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.Limited;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jaxb.mapping.Fixed;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import de.focus_shift.jollyday.jaxb.mapping.RelativeToFixed;
+import de.focus_shift.jollyday.jaxb.mapping.Weekday;
+import de.focus_shift.jollyday.jaxb.mapping.When;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbChristianHolidayTest {
+
+  @Test
+  void ensureDateIsSetAndMappedCorrectly() {
+
+    final Fixed firstJanuary = new Fixed();
+    firstJanuary.setDay(1);
+    firstJanuary.setMonth(Month.JANUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setWeekday(Weekday.MONDAY);
+    relativeToFixed.setWhen(When.AFTER);
+    relativeToFixed.setDate(firstJanuary);
+    relativeToFixed.setEvery(HolidayCycleType.EVEN_YEARS);
+    relativeToFixed.setDescriptionPropertiesKey("description");
+    relativeToFixed.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    relativeToFixed.setValidFrom(2000);
+    relativeToFixed.setValidTo(2001);
+    final JaxbRelativeToFixed jaxbRelativeToFixed = new JaxbRelativeToFixed(relativeToFixed);
+
+    assertThat(jaxbRelativeToFixed.date().day()).isEqualTo(new JaxbFixed(firstJanuary).day());
+    assertThat(jaxbRelativeToFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbRelativeToFixed.when()).isEqualTo(Relation.AFTER);
+    assertThat(jaxbRelativeToFixed.cycle()).isEqualTo(Limited.YearCycle.EVEN_YEARS);
+    assertThat(jaxbRelativeToFixed.descriptionPropertiesKey()).isEqualTo("description");
+    assertThat(jaxbRelativeToFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbRelativeToFixed.validFrom()).isEqualTo(Year.of(2000));
+    assertThat(jaxbRelativeToFixed.validTo()).isEqualTo(Year.of(2001));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+
+    final Fixed firstJanuary = new Fixed();
+    firstJanuary.setDay(1);
+    firstJanuary.setMonth(Month.JANUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setDate(firstJanuary);
+    final JaxbRelativeToFixed jaxbRelativeToFixed = new JaxbRelativeToFixed(relativeToFixed);
+
+    assertThat(jaxbRelativeToFixed.date().day()).isEqualTo(new JaxbFixed(firstJanuary).day());
+    assertThat(jaxbRelativeToFixed.weekday()).isNull();
+    assertThat(jaxbRelativeToFixed.when()).isNull();
+    assertThat(jaxbRelativeToFixed.cycle()).isEqualTo(Limited.YearCycle.EVERY_YEAR);
+    assertThat(jaxbRelativeToFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbRelativeToFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbRelativeToFixed.validFrom()).isNull();
+    assertThat(jaxbRelativeToFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbConfigurationTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbConfigurationTest.java
new file mode 100644
index 00000000..063a9b1d
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbConfigurationTest.java
@@ -0,0 +1,36 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.jaxb.mapping.Configuration;
+import de.focus_shift.jollyday.jaxb.mapping.Holidays;
+import de.focus_shift.jollyday.jaxb.mapping.Sources;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbConfigurationTest {
+
+  @Test
+  void ensuresCorrectMapping() {
+
+    final Configuration configuration = new Configuration();
+    configuration.setDescription("description");
+    configuration.setHierarchy("hierarchy");
+
+    final Configuration subConfiguration = new Configuration();
+    subConfiguration.setHierarchy("subHierarchy");
+    configuration.getSubConfigurations().add(subConfiguration);
+
+    final Holidays holidays = new Holidays();
+    configuration.setHolidays(holidays);
+
+    final Sources sources = new Sources();
+    configuration.setSources(sources);
+
+    final JaxbConfiguration sut = new JaxbConfiguration(configuration);
+    assertThat(sut.holidays()).isNotNull();
+    assertThat(sut.subConfigurations().findFirst())
+      .hasValueSatisfying(subConf -> assertThat(subConf.hierarchy()).isEqualTo("subHierarchy"));
+    assertThat(sut.hierarchy()).isEqualTo("hierarchy");
+    assertThat(sut.description()).isEqualTo("description");
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbEthiopianOrthodoxHolidayTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbEthiopianOrthodoxHolidayTest.java
new file mode 100644
index 00000000..61f87010
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbEthiopianOrthodoxHolidayTest.java
@@ -0,0 +1,48 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.EthiopianOrthodoxHoliday.EthiopianOrthodoxHolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jaxb.mapping.EthiopianOrthodoxHoliday;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayType;
+import org.junit.jupiter.api.Test;
+
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbEthiopianOrthodoxHolidayTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final EthiopianOrthodoxHoliday ethiopianOrthodoxHoliday = new EthiopianOrthodoxHoliday();
+    ethiopianOrthodoxHoliday.setType(de.focus_shift.jollyday.jaxb.mapping.EthiopianOrthodoxHolidayType.TIMKAT);
+    ethiopianOrthodoxHoliday.setEvery(HolidayCycleType.ODD_YEARS);
+    ethiopianOrthodoxHoliday.setDescriptionPropertiesKey("ethiopian.description");
+    ethiopianOrthodoxHoliday.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    ethiopianOrthodoxHoliday.setValidFrom(2010);
+    ethiopianOrthodoxHoliday.setValidTo(2020);
+
+    final JaxbEthiopianOrthodoxHoliday jaxbEthiopianOrthodoxHoliday = new JaxbEthiopianOrthodoxHoliday(ethiopianOrthodoxHoliday);
+    assertThat(jaxbEthiopianOrthodoxHoliday.type()).isEqualTo(EthiopianOrthodoxHolidayType.TIMKAT);
+    assertThat(jaxbEthiopianOrthodoxHoliday.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbEthiopianOrthodoxHoliday.descriptionPropertiesKey()).isEqualTo("ethiopian.description");
+    assertThat(jaxbEthiopianOrthodoxHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbEthiopianOrthodoxHoliday.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jaxbEthiopianOrthodoxHoliday.validTo()).isEqualTo(Year.of(2020));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final EthiopianOrthodoxHoliday ethiopianOrthodoxHoliday = new EthiopianOrthodoxHoliday();
+    ethiopianOrthodoxHoliday.setType(de.focus_shift.jollyday.jaxb.mapping.EthiopianOrthodoxHolidayType.TIMKAT);
+
+    final JaxbEthiopianOrthodoxHoliday jaxbEthiopianOrthodoxHoliday = new JaxbEthiopianOrthodoxHoliday(ethiopianOrthodoxHoliday);
+    assertThat(jaxbEthiopianOrthodoxHoliday.type()).isEqualTo(EthiopianOrthodoxHolidayType.TIMKAT);
+    assertThat(jaxbEthiopianOrthodoxHoliday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbEthiopianOrthodoxHoliday.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbEthiopianOrthodoxHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbEthiopianOrthodoxHoliday.validFrom()).isNull();
+    assertThat(jaxbEthiopianOrthodoxHoliday.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedTest.java
new file mode 100644
index 00000000..10850885
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedTest.java
@@ -0,0 +1,55 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jaxb.mapping.Fixed;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import org.junit.jupiter.api.Test;
+
+import java.time.MonthDay;
+import java.time.Year;
+
+import static java.time.Month.DECEMBER;
+import static java.time.Month.JANUARY;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(25);
+    fixed.setMonth(Month.DECEMBER);
+    fixed.setEvery(HolidayCycleType.ODD_YEARS);
+    fixed.setDescriptionPropertiesKey("fixed.description");
+    fixed.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    fixed.setValidFrom(2010);
+    fixed.setValidTo(2020);
+
+    final JaxbFixed jaxbFixed = new JaxbFixed(fixed);
+    assertThat(jaxbFixed.day()).isEqualTo(MonthDay.of(DECEMBER, 25));
+    assertThat(jaxbFixed.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbFixed.descriptionPropertiesKey()).isEqualTo("fixed.description");
+    assertThat(jaxbFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbFixed.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jaxbFixed.validTo()).isEqualTo(Year.of(2020));
+    assertThat(jaxbFixed.conditions()).isEmpty();
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(1);
+    fixed.setMonth(Month.JANUARY);
+
+    final JaxbFixed jaxbFixed = new JaxbFixed(fixed);
+    assertThat(jaxbFixed.day()).isEqualTo(MonthDay.of(JANUARY, 1));
+    assertThat(jaxbFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbFixed.validFrom()).isNull();
+    assertThat(jaxbFixed.validTo()).isNull();
+    assertThat(jaxbFixed.conditions()).isEmpty();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayBetweenFixedTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayBetweenFixedTest.java
new file mode 100644
index 00000000..a7c8720d
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayBetweenFixedTest.java
@@ -0,0 +1,78 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jaxb.mapping.Fixed;
+import de.focus_shift.jollyday.jaxb.mapping.FixedWeekdayBetweenFixed;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import de.focus_shift.jollyday.jaxb.mapping.Weekday;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.MonthDay;
+import java.time.Year;
+
+import static de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY;
+import static java.time.Month.JANUARY;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbFixedWeekdayBetweenFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed from = new Fixed();
+    from.setDay(1);
+    from.setMonth(Month.JANUARY);
+
+    final Fixed to = new Fixed();
+    to.setDay(10);
+    to.setMonth(Month.JANUARY);
+
+    final FixedWeekdayBetweenFixed fixedWeekdayBetweenFixed = new FixedWeekdayBetweenFixed();
+    fixedWeekdayBetweenFixed.setFrom(from);
+    fixedWeekdayBetweenFixed.setTo(to);
+    fixedWeekdayBetweenFixed.setWeekday(Weekday.MONDAY);
+    fixedWeekdayBetweenFixed.setEvery(HolidayCycleType.ODD_YEARS);
+    fixedWeekdayBetweenFixed.setDescriptionPropertiesKey("between.description");
+    fixedWeekdayBetweenFixed.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    fixedWeekdayBetweenFixed.setValidFrom(2010);
+    fixedWeekdayBetweenFixed.setValidTo(2020);
+
+    final JaxbFixedWeekdayBetweenFixed jaxbFixedWeekdayBetweenFixed = new JaxbFixedWeekdayBetweenFixed(fixedWeekdayBetweenFixed);
+    assertThat(jaxbFixedWeekdayBetweenFixed.from().day()).isEqualTo(MonthDay.of(JANUARY, 1));
+    assertThat(jaxbFixedWeekdayBetweenFixed.to().day()).isEqualTo(MonthDay.of(JANUARY, 10));
+    assertThat(jaxbFixedWeekdayBetweenFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbFixedWeekdayBetweenFixed.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbFixedWeekdayBetweenFixed.descriptionPropertiesKey()).isEqualTo("between.description");
+    assertThat(jaxbFixedWeekdayBetweenFixed.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbFixedWeekdayBetweenFixed.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jaxbFixedWeekdayBetweenFixed.validTo()).isEqualTo(Year.of(2020));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed from = new Fixed();
+    from.setDay(1);
+    from.setMonth(Month.JANUARY);
+
+    final Fixed to = new Fixed();
+    to.setDay(10);
+    to.setMonth(Month.JANUARY);
+
+    final FixedWeekdayBetweenFixed fixedWeekdayBetweenFixed = new FixedWeekdayBetweenFixed();
+    fixedWeekdayBetweenFixed.setFrom(from);
+    fixedWeekdayBetweenFixed.setTo(to);
+    fixedWeekdayBetweenFixed.setWeekday(Weekday.MONDAY);
+
+    final JaxbFixedWeekdayBetweenFixed jaxbFixedWeekdayBetweenFixed = new JaxbFixedWeekdayBetweenFixed(fixedWeekdayBetweenFixed);
+    assertThat(jaxbFixedWeekdayBetweenFixed.from().day()).isEqualTo(MonthDay.of(JANUARY, 1));
+    assertThat(jaxbFixedWeekdayBetweenFixed.to().day()).isEqualTo(MonthDay.of(JANUARY, 10));
+    assertThat(jaxbFixedWeekdayBetweenFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbFixedWeekdayBetweenFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbFixedWeekdayBetweenFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbFixedWeekdayBetweenFixed.holidayType()).isEqualTo(PUBLIC_HOLIDAY);
+    assertThat(jaxbFixedWeekdayBetweenFixed.validFrom()).isNull();
+    assertThat(jaxbFixedWeekdayBetweenFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayInMonthTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayInMonthTest.java
new file mode 100644
index 00000000..e63db1d5
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayInMonthTest.java
@@ -0,0 +1,60 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Occurrence;
+import de.focus_shift.jollyday.jaxb.mapping.FixedWeekdayInMonth;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import de.focus_shift.jollyday.jaxb.mapping.Weekday;
+import de.focus_shift.jollyday.jaxb.mapping.Which;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbFixedWeekdayInMonthTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final FixedWeekdayInMonth fixedWeekdayInMonth = new FixedWeekdayInMonth();
+    fixedWeekdayInMonth.setWeekday(Weekday.MONDAY);
+    fixedWeekdayInMonth.setMonth(Month.MARCH);
+    fixedWeekdayInMonth.setWhich(Which.FIRST);
+    fixedWeekdayInMonth.setEvery(HolidayCycleType.ODD_YEARS);
+    fixedWeekdayInMonth.setDescriptionPropertiesKey("weekdayinmonth.description");
+    fixedWeekdayInMonth.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    fixedWeekdayInMonth.setValidFrom(2012);
+    fixedWeekdayInMonth.setValidTo(2022);
+
+    final JaxbFixedWeekdayInMonth jaxbFixedWeekdayInMonth = new JaxbFixedWeekdayInMonth(fixedWeekdayInMonth);
+    assertThat(jaxbFixedWeekdayInMonth.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbFixedWeekdayInMonth.month()).isEqualTo(java.time.Month.MARCH);
+    assertThat(jaxbFixedWeekdayInMonth.which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jaxbFixedWeekdayInMonth.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbFixedWeekdayInMonth.descriptionPropertiesKey()).isEqualTo("weekdayinmonth.description");
+    assertThat(jaxbFixedWeekdayInMonth.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbFixedWeekdayInMonth.validFrom()).isEqualTo(Year.of(2012));
+    assertThat(jaxbFixedWeekdayInMonth.validTo()).isEqualTo(Year.of(2022));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final FixedWeekdayInMonth mapping = new FixedWeekdayInMonth();
+    mapping.setWeekday(Weekday.FRIDAY);
+    mapping.setMonth(Month.JUNE);
+    mapping.setWhich(Which.LAST);
+
+    final JaxbFixedWeekdayInMonth holiday = new JaxbFixedWeekdayInMonth(mapping);
+    assertThat(holiday.weekday()).isEqualTo(DayOfWeek.FRIDAY);
+    assertThat(holiday.month()).isEqualTo(java.time.Month.JUNE);
+    assertThat(holiday.which()).isEqualTo(Occurrence.LAST);
+    assertThat(holiday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(holiday.descriptionPropertiesKey()).isNull();
+    assertThat(holiday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(holiday.validFrom()).isNull();
+    assertThat(holiday.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayRelativeToFixedTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayRelativeToFixedTest.java
new file mode 100644
index 00000000..654b877a
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbFixedWeekdayRelativeToFixedTest.java
@@ -0,0 +1,77 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Occurrence;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jaxb.mapping.Fixed;
+import de.focus_shift.jollyday.jaxb.mapping.FixedWeekdayRelativeToFixed;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import de.focus_shift.jollyday.jaxb.mapping.Weekday;
+import de.focus_shift.jollyday.jaxb.mapping.When;
+import de.focus_shift.jollyday.jaxb.mapping.Which;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.MonthDay;
+import java.time.Year;
+
+import static de.focus_shift.jollyday.jaxb.mapping.HolidayType.BANK_HOLIDAY;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbFixedWeekdayRelativeToFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(15);
+    fixed.setMonth(Month.APRIL);
+
+    final FixedWeekdayRelativeToFixed fixedWeekdayRelativeToFixed = new FixedWeekdayRelativeToFixed();
+    fixedWeekdayRelativeToFixed.setDay(fixed);
+    fixedWeekdayRelativeToFixed.setWeekday(Weekday.THURSDAY);
+    fixedWeekdayRelativeToFixed.setWhen(When.BEFORE);
+    fixedWeekdayRelativeToFixed.setWhich(Which.SECOND);
+    fixedWeekdayRelativeToFixed.setEvery(HolidayCycleType.EVEN_YEARS);
+    fixedWeekdayRelativeToFixed.setDescriptionPropertiesKey("relative.description");
+    fixedWeekdayRelativeToFixed.setLocalizedType(BANK_HOLIDAY);
+    fixedWeekdayRelativeToFixed.setValidFrom(2011);
+    fixedWeekdayRelativeToFixed.setValidTo(2021);
+
+    final JaxbFixedWeekdayRelativeToFixed jaxbFixedWeekdayRelativeToFixed = new JaxbFixedWeekdayRelativeToFixed(fixedWeekdayRelativeToFixed);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.day().day()).isEqualTo(MonthDay.of(java.time.Month.APRIL, 15));
+    assertThat(jaxbFixedWeekdayRelativeToFixed.weekday()).isEqualTo(DayOfWeek.THURSDAY);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.when()).isEqualTo(Relation.BEFORE);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.which()).isEqualTo(Occurrence.SECOND);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.cycle()).isEqualTo(YearCycle.EVEN_YEARS);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.descriptionPropertiesKey()).isEqualTo("relative.description");
+    assertThat(jaxbFixedWeekdayRelativeToFixed.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.validFrom()).isEqualTo(Year.of(2011));
+    assertThat(jaxbFixedWeekdayRelativeToFixed.validTo()).isEqualTo(Year.of(2021));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(5);
+    fixed.setMonth(Month.MAY);
+
+    final FixedWeekdayRelativeToFixed fixedWeekdayRelativeToFixed = new FixedWeekdayRelativeToFixed();
+    fixedWeekdayRelativeToFixed.setDay(fixed);
+    fixedWeekdayRelativeToFixed.setWeekday(Weekday.MONDAY);
+    fixedWeekdayRelativeToFixed.setWhen(When.AFTER);
+    fixedWeekdayRelativeToFixed.setWhich(Which.FIRST);
+
+    final JaxbFixedWeekdayRelativeToFixed jaxbFixedWeekdayRelativeToFixed = new JaxbFixedWeekdayRelativeToFixed(fixedWeekdayRelativeToFixed);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.day().day()).isEqualTo(MonthDay.of(java.time.Month.MAY, 5));
+    assertThat(jaxbFixedWeekdayRelativeToFixed.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.when()).isEqualTo(Relation.AFTER);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbFixedWeekdayRelativeToFixed.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbFixedWeekdayRelativeToFixed.validFrom()).isNull();
+    assertThat(jaxbFixedWeekdayRelativeToFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbIslamicHolidayTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbIslamicHolidayTest.java
new file mode 100644
index 00000000..f1926709
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbIslamicHolidayTest.java
@@ -0,0 +1,50 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.IslamicHoliday.IslamicHolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayType;
+import de.focus_shift.jollyday.jaxb.mapping.IslamicHoliday;
+import org.junit.jupiter.api.Test;
+
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbIslamicHolidayTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final IslamicHoliday islamicHoliday = new IslamicHoliday();
+    islamicHoliday.setType(de.focus_shift.jollyday.jaxb.mapping.IslamicHolidayType.ID_UL_ADHA);
+    islamicHoliday.setEvery(HolidayCycleType.ODD_YEARS);
+    islamicHoliday.setDescriptionPropertiesKey("islamic.description");
+    islamicHoliday.setLocalizedType(HolidayType.BANK_HOLIDAY);
+    islamicHoliday.setValidFrom(2015);
+    islamicHoliday.setValidTo(2025);
+
+    final JaxbIslamicHoliday jaxbIslamicHoliday = new JaxbIslamicHoliday(islamicHoliday);
+    assertThat(jaxbIslamicHoliday.type()).isEqualTo(IslamicHolidayType.ID_UL_ADHA);
+    assertThat(jaxbIslamicHoliday.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbIslamicHoliday.descriptionPropertiesKey()).isEqualTo("islamic.description");
+    assertThat(jaxbIslamicHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbIslamicHoliday.validFrom()).isEqualTo(Year.of(2015));
+    assertThat(jaxbIslamicHoliday.validTo()).isEqualTo(Year.of(2025));
+    assertThat(jaxbIslamicHoliday.conditions()).isEmpty();
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final IslamicHoliday islamicHoliday = new IslamicHoliday();
+    islamicHoliday.setType(de.focus_shift.jollyday.jaxb.mapping.IslamicHolidayType.ID_UL_ADHA);
+
+    final JaxbIslamicHoliday jaxbIslamicHoliday = new JaxbIslamicHoliday(islamicHoliday);
+    assertThat(jaxbIslamicHoliday.type()).isEqualTo(IslamicHolidayType.ID_UL_ADHA);
+    assertThat(jaxbIslamicHoliday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbIslamicHoliday.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbIslamicHoliday.holidayType()).isEqualTo(de.focus_shift.jollyday.core.HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbIslamicHoliday.validFrom()).isNull();
+    assertThat(jaxbIslamicHoliday.validTo()).isNull();
+    assertThat(jaxbIslamicHoliday.conditions()).isEmpty();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbMovingConditionTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbMovingConditionTest.java
new file mode 100644
index 00000000..e6553563
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbMovingConditionTest.java
@@ -0,0 +1,37 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.spi.Movable;
+import de.focus_shift.jollyday.jaxb.mapping.MovingCondition;
+import de.focus_shift.jollyday.jaxb.mapping.Weekday;
+import de.focus_shift.jollyday.jaxb.mapping.With;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class JaxbMovingConditionTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final MovingCondition movingCondition = new MovingCondition();
+    movingCondition.setSubstitute(Weekday.SATURDAY);
+    movingCondition.setWith(With.NEXT);
+    movingCondition.setWeekday(Weekday.MONDAY);
+
+    final JaxbMovingCondition jaxbMovingCondition = new JaxbMovingCondition(movingCondition);
+    assertThat(jaxbMovingCondition.substitute()).isEqualTo(DayOfWeek.SATURDAY);
+    assertThat(jaxbMovingCondition.with()).isEqualTo(Movable.MovingCondition.With.NEXT);
+    assertThat(jaxbMovingCondition.weekday()).isEqualTo(DayOfWeek.MONDAY);
+  }
+
+  @Test
+  void ensureNullPointerOnUnsetValues() {
+    final MovingCondition movingCondition = new MovingCondition();
+    final JaxbMovingCondition jaxbMovingCondition = new JaxbMovingCondition(movingCondition);
+    assertThrows(NullPointerException.class, jaxbMovingCondition::substitute);
+    assertThrows(NullPointerException.class, jaxbMovingCondition::with);
+    assertThrows(NullPointerException.class, jaxbMovingCondition::weekday);
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToEasterSundayTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToEasterSundayTest.java
new file mode 100644
index 00000000..205ffaea
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToEasterSundayTest.java
@@ -0,0 +1,54 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.jaxb.mapping.ChronologyType;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.RelativeToEasterSunday;
+import org.junit.jupiter.api.Test;
+import org.threeten.extra.Days;
+import org.threeten.extra.chrono.JulianChronology;
+
+import java.time.Year;
+import java.time.chrono.IsoChronology;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbRelativeToEasterSundayTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final RelativeToEasterSunday relativeToEasterSunday = new RelativeToEasterSunday();
+    relativeToEasterSunday.setDays(10);
+    relativeToEasterSunday.setChronology(ChronologyType.JULIAN);
+    relativeToEasterSunday.setEvery(HolidayCycleType.ODD_YEARS);
+    relativeToEasterSunday.setDescriptionPropertiesKey("easter.description");
+    relativeToEasterSunday.setLocalizedType(de.focus_shift.jollyday.jaxb.mapping.HolidayType.BANK_HOLIDAY);
+    relativeToEasterSunday.setValidFrom(2015);
+    relativeToEasterSunday.setValidTo(2025);
+
+    final JaxbRelativeToEasterSunday jaxbRelativeToEasterSunday = new JaxbRelativeToEasterSunday(relativeToEasterSunday);
+    assertThat(jaxbRelativeToEasterSunday.days()).isEqualTo(Days.of(10));
+    assertThat(jaxbRelativeToEasterSunday.chronology()).isEqualTo(JulianChronology.INSTANCE);
+    assertThat(jaxbRelativeToEasterSunday.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbRelativeToEasterSunday.descriptionPropertiesKey()).isEqualTo("easter.description");
+    assertThat(jaxbRelativeToEasterSunday.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbRelativeToEasterSunday.validFrom()).isEqualTo(Year.of(2015));
+    assertThat(jaxbRelativeToEasterSunday.validTo()).isEqualTo(Year.of(2025));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final RelativeToEasterSunday relativeToEasterSunday = new RelativeToEasterSunday();
+    relativeToEasterSunday.setDays(-2);
+
+    final JaxbRelativeToEasterSunday jaxbRelativeToEasterSunday = new JaxbRelativeToEasterSunday(relativeToEasterSunday);
+    assertThat(jaxbRelativeToEasterSunday.days()).isEqualTo(Days.of(-2));
+    assertThat(jaxbRelativeToEasterSunday.chronology()).isEqualTo(IsoChronology.INSTANCE);
+    assertThat(jaxbRelativeToEasterSunday.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbRelativeToEasterSunday.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbRelativeToEasterSunday.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbRelativeToEasterSunday.validFrom()).isNull();
+    assertThat(jaxbRelativeToEasterSunday.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToFixedTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToFixedTest.java
new file mode 100644
index 00000000..4250827d
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToFixedTest.java
@@ -0,0 +1,67 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jaxb.mapping.Fixed;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import de.focus_shift.jollyday.jaxb.mapping.RelativeToFixed;
+import de.focus_shift.jollyday.jaxb.mapping.When;
+import org.junit.jupiter.api.Test;
+import org.threeten.extra.Days;
+
+import java.time.MonthDay;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbRelativeToFixedTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(1);
+    fixed.setMonth(Month.JANUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setDate(fixed);
+    relativeToFixed.setDays(3);
+    relativeToFixed.setWhen(When.AFTER);
+    relativeToFixed.setEvery(HolidayCycleType.ODD_YEARS);
+    relativeToFixed.setDescriptionPropertiesKey("relative.fixed.description");
+    relativeToFixed.setLocalizedType(de.focus_shift.jollyday.jaxb.mapping.HolidayType.BANK_HOLIDAY);
+    relativeToFixed.setValidFrom(2000);
+    relativeToFixed.setValidTo(2020);
+
+    final JaxbRelativeToFixed jaxbRelativeToFixed = new JaxbRelativeToFixed(relativeToFixed);
+    assertThat(jaxbRelativeToFixed.date().day()).isEqualTo(MonthDay.of(java.time.Month.JANUARY, 1));
+    assertThat(jaxbRelativeToFixed.days()).isEqualTo(Days.of(3));
+    assertThat(jaxbRelativeToFixed.when()).isEqualTo(Relation.AFTER);
+    assertThat(jaxbRelativeToFixed.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+    assertThat(jaxbRelativeToFixed.descriptionPropertiesKey()).isEqualTo("relative.fixed.description");
+    assertThat(jaxbRelativeToFixed.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbRelativeToFixed.validFrom()).isEqualTo(Year.of(2000));
+    assertThat(jaxbRelativeToFixed.validTo()).isEqualTo(Year.of(2020));
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final Fixed fixed = new Fixed();
+    fixed.setDay(10);
+    fixed.setMonth(Month.FEBRUARY);
+
+    final RelativeToFixed relativeToFixed = new RelativeToFixed();
+    relativeToFixed.setDate(fixed);
+
+    final JaxbRelativeToFixed jaxbRelativeToFixed = new JaxbRelativeToFixed(relativeToFixed);
+    assertThat(jaxbRelativeToFixed.date().day()).isEqualTo(MonthDay.of(java.time.Month.FEBRUARY, 10));
+    assertThat(jaxbRelativeToFixed.days()).isNull();
+    assertThat(jaxbRelativeToFixed.when()).isNull();
+    assertThat(jaxbRelativeToFixed.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+    assertThat(jaxbRelativeToFixed.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbRelativeToFixed.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbRelativeToFixed.validFrom()).isNull();
+    assertThat(jaxbRelativeToFixed.validTo()).isNull();
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToWeekdayInMonthTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToWeekdayInMonthTest.java
new file mode 100644
index 00000000..90664d4e
--- /dev/null
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbRelativeToWeekdayInMonthTest.java
@@ -0,0 +1,77 @@
+package de.focus_shift.jollyday.jaxb;
+
+import de.focus_shift.jollyday.core.HolidayType;
+import de.focus_shift.jollyday.core.spi.Limited.YearCycle;
+import de.focus_shift.jollyday.core.spi.Occurrence;
+import de.focus_shift.jollyday.core.spi.Relation;
+import de.focus_shift.jollyday.jaxb.mapping.FixedWeekdayInMonth;
+import de.focus_shift.jollyday.jaxb.mapping.HolidayCycleType;
+import de.focus_shift.jollyday.jaxb.mapping.Month;
+import de.focus_shift.jollyday.jaxb.mapping.RelativeToWeekdayInMonth;
+import de.focus_shift.jollyday.jaxb.mapping.Weekday;
+import de.focus_shift.jollyday.jaxb.mapping.When;
+import de.focus_shift.jollyday.jaxb.mapping.Which;
+import org.junit.jupiter.api.Test;
+
+import java.time.DayOfWeek;
+import java.time.Year;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class JaxbRelativeToWeekdayInMonthTest {
+
+  @Test
+  void ensureFieldsAreSetAndMappedCorrectly() {
+    final FixedWeekdayInMonth fixedWeekdayInMonth = new FixedWeekdayInMonth();
+    fixedWeekdayInMonth.setMonth(Month.MARCH);
+    fixedWeekdayInMonth.setWhich(Which.FIRST);
+    fixedWeekdayInMonth.setWeekday(Weekday.FRIDAY);
+
+    final RelativeToWeekdayInMonth relativeToWeekdayInMonth = new RelativeToWeekdayInMonth();
+    relativeToWeekdayInMonth.setFixedWeekday(fixedWeekdayInMonth);
+    relativeToWeekdayInMonth.setWeekday(Weekday.MONDAY);
+    relativeToWeekdayInMonth.setWhen(When.BEFORE);
+    relativeToWeekdayInMonth.setDescriptionPropertiesKey("weekdayinmonth.description");
+    relativeToWeekdayInMonth.setLocalizedType(de.focus_shift.jollyday.jaxb.mapping.HolidayType.BANK_HOLIDAY);
+    relativeToWeekdayInMonth.setValidFrom(2010);
+    relativeToWeekdayInMonth.setValidTo(2020);
+    relativeToWeekdayInMonth.setEvery(HolidayCycleType.ODD_YEARS);
+
+    final JaxbRelativeToWeekdayInMonth jaxbRelativeToWeekdayInMonth = new JaxbRelativeToWeekdayInMonth(relativeToWeekdayInMonth);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekdayInMonth().which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekdayInMonth().weekday()).isEqualTo(DayOfWeek.FRIDAY);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekdayInMonth().month()).isEqualTo(java.time.Month.MARCH);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbRelativeToWeekdayInMonth.when()).isEqualTo(Relation.BEFORE);
+    assertThat(jaxbRelativeToWeekdayInMonth.descriptionPropertiesKey()).isEqualTo("weekdayinmonth.description");
+    assertThat(jaxbRelativeToWeekdayInMonth.holidayType()).isEqualTo(HolidayType.BANK_HOLIDAY);
+    assertThat(jaxbRelativeToWeekdayInMonth.validFrom()).isEqualTo(Year.of(2010));
+    assertThat(jaxbRelativeToWeekdayInMonth.validTo()).isEqualTo(Year.of(2020));
+    assertThat(jaxbRelativeToWeekdayInMonth.cycle()).isEqualTo(YearCycle.ODD_YEARS);
+  }
+
+  @Test
+  void ensureToReturnNullOrDefaultValuesOnNotSetValues() {
+    final FixedWeekdayInMonth fixedWeekdayInMonth = new FixedWeekdayInMonth();
+    fixedWeekdayInMonth.setMonth(Month.APRIL);
+    fixedWeekdayInMonth.setWhich(Which.FIRST);
+    fixedWeekdayInMonth.setWeekday(Weekday.SUNDAY);
+
+    final RelativeToWeekdayInMonth relativeToWeekdayInMonth = new RelativeToWeekdayInMonth();
+    relativeToWeekdayInMonth.setFixedWeekday(fixedWeekdayInMonth);
+    relativeToWeekdayInMonth.setWeekday(Weekday.MONDAY);
+    relativeToWeekdayInMonth.setWhen(When.AFTER);
+
+    final JaxbRelativeToWeekdayInMonth jaxbRelativeToWeekdayInMonth = new JaxbRelativeToWeekdayInMonth(relativeToWeekdayInMonth);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekdayInMonth().which()).isEqualTo(Occurrence.FIRST);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekdayInMonth().weekday()).isEqualTo(DayOfWeek.SUNDAY);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekdayInMonth().month()).isEqualTo(java.time.Month.APRIL);
+    assertThat(jaxbRelativeToWeekdayInMonth.weekday()).isEqualTo(DayOfWeek.MONDAY);
+    assertThat(jaxbRelativeToWeekdayInMonth.when()).isEqualTo(Relation.AFTER);
+    assertThat(jaxbRelativeToWeekdayInMonth.descriptionPropertiesKey()).isNull();
+    assertThat(jaxbRelativeToWeekdayInMonth.holidayType()).isEqualTo(HolidayType.PUBLIC_HOLIDAY);
+    assertThat(jaxbRelativeToWeekdayInMonth.validFrom()).isNull();
+    assertThat(jaxbRelativeToWeekdayInMonth.validTo()).isNull();
+    assertThat(jaxbRelativeToWeekdayInMonth.cycle()).isEqualTo(YearCycle.EVERY_YEAR);
+  }
+}
diff --git a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/test/JaxbXMLMapperTest.java b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbXMLMapperTest.java
similarity index 92%
rename from jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/test/JaxbXMLMapperTest.java
rename to jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbXMLMapperTest.java
index d9596638..fafdf6c3 100644
--- a/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/test/JaxbXMLMapperTest.java
+++ b/jollyday-jaxb/src/test/java/de/focus_shift/jollyday/jaxb/JaxbXMLMapperTest.java
@@ -1,6 +1,5 @@
-package de.focus_shift.jollyday.jaxb.test;
+package de.focus_shift.jollyday.jaxb;
 
-import de.focus_shift.jollyday.jaxb.JaxbXMLMapper;
 import de.focus_shift.jollyday.jaxb.mapping.Configuration;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
diff --git a/jollyday-jaxb/src/test/java/module-info.java b/jollyday-jaxb/src/test/java/module-info.java
deleted file mode 100644
index dde0a324..00000000
--- a/jollyday-jaxb/src/test/java/module-info.java
+++ /dev/null
@@ -1,14 +0,0 @@
-module de.focus_shift.jollyday.jaxb.test {
-
-  opens de.focus_shift.jollyday.jaxb.test to
-    org.junit.platform.commons;
-
-  requires de.focus_shift.jollyday.core;
-  requires de.focus_shift.jollyday.jaxb;
-  requires jakarta.xml.bind;
-  requires org.assertj.core;
-  requires org.junit.jupiter.api;
-  requires org.junit.jupiter.params;
-  requires org.mockito.junit.jupiter;
-  requires org.mockito;
-}