From e8ba9baff7536fc4565719cbc130ef81995d15bb Mon Sep 17 00:00:00 2001
From: Thomas <>
Date: Thu, 1 Feb 2024 13:46:53 +0100
Subject: feat(core): add Jackson Joda module

Hint: Modules will be only loaded if it is available on classpath
---
 .../eaaf/core/impl/utils/DefaultJsonMapper.java    | 68 +++++++++++++++++++++-
 1 file changed, 66 insertions(+), 2 deletions(-)

(limited to 'eaaf_core/src')

diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DefaultJsonMapper.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DefaultJsonMapper.java
index 8303e860..92bf94d4 100644
--- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DefaultJsonMapper.java
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DefaultJsonMapper.java
@@ -1,6 +1,8 @@
 package at.gv.egiz.eaaf.core.impl.utils;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
 import com.fasterxml.jackson.annotation.PropertyAccessor;
@@ -9,10 +11,10 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.type.TypeFactory;
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 
 import at.gv.egiz.eaaf.core.exceptions.EaafJsonMapperException;
 import lombok.Getter;
@@ -27,6 +29,11 @@ import lombok.extern.slf4j.Slf4j;
 @Slf4j
 public final class DefaultJsonMapper {
 
+  private static final String JAVA_TIME_MODULE_CLASS = "com.fasterxml.jackson.datatype.jsr310.JavaTimeModule";
+  private static final String JAVA_TIME_MODULE_CONSTRUCTOR = "JavaTimeModule";
+  private static final String JODA_TIME_MODULE_CLASS = "com.fasterxml.jackson.datatype.joda.JodaModule";
+  private static final String JODA_TIME_MODULE_CONSTRUCTOR = "JodaModule";
+
   @Getter
   private static final ObjectMapper jsonMapper = new ObjectMapper();
 
@@ -39,7 +46,9 @@ public final class DefaultJsonMapper {
     jsonMapper.setVisibility(PropertyAccessor.GETTER, Visibility.PUBLIC_ONLY);
     jsonMapper.setVisibility(PropertyAccessor.IS_GETTER, Visibility.PUBLIC_ONLY);
 
-    jsonMapper.registerModule(new JavaTimeModule());
+    registerModuleIfAvailable(JAVA_TIME_MODULE_CLASS, JAVA_TIME_MODULE_CONSTRUCTOR);
+    registerModuleIfAvailable(JODA_TIME_MODULE_CLASS, JODA_TIME_MODULE_CONSTRUCTOR);
+
     jsonMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
 
   }
@@ -101,6 +110,61 @@ public final class DefaultJsonMapper {
       throw new EaafJsonMapperException(e.getMessage(), e);
 
     }
+  }
+
+  private static void registerModuleIfAvailable(String fullModuleClasspath, String constructorName) {
+    Module module = checkAndLoadModule(fullModuleClasspath, constructorName);
+    if (module != null) {
+      jsonMapper.registerModule(module);
+      log.info("Register Jackson module: {}", module.getModuleName());
+
+    } else {
+      log.debug("Skipping Jackson module not on classpath: {}", fullModuleClasspath);
+
+    }
+  }
+
+  private static Module checkAndLoadModule(String fullModuleClasspath, String constructorName) {
+    Class<?> clazz = getModuleClass(fullModuleClasspath);
+    if (clazz != null) {
+      return getModuleInstance(clazz, constructorName);
+    }
+
+    return null;
+  }
+
+  private static Module getModuleInstance(Class<?> clazz, String constructorName) {
+    try {
+      final Method constructor = clazz.getMethod(constructorName, new Class[] {});
+      if (constructor != null) {
+        log.trace("Found method: {} for class:{}. Creating instanze .... ",
+            constructorName, clazz.getName());
+        final Object rawModule = constructor.invoke(clazz);
+        return rawModule instanceof Module ? (Module) rawModule : null;
 
+      } else {
+        log.warn("Find module:{}, but Constructor:{} looks wrong!", clazz.getName(), constructorName);
+
+      }
+
+    } catch (NoSuchMethodException | SecurityException | IllegalAccessException
+        | IllegalArgumentException | InvocationTargetException e) {
+      log.debug("Can not create instanze of Jackson module: {}. Reason: {}", clazz.getName(), e.getMessage());
+      log.trace("Detailed error", e);
+
+    }
+    return null;
+
+  }
+
+  private static Class<?> getModuleClass(String fullClassName) {
+    try {
+      return Class.forName(fullClassName);
+
+    } catch (final ClassNotFoundException e1) {
+      log.debug("No {} implemenation in ClassPath. Jackson module will not be available", fullClassName);
+      return null;
+
+    }
   }
 }
-- 
cgit v1.2.3