diff --git a/pom.xml b/pom.xml index dffcb646c..970c69c94 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,11 @@ jackson-dataformat-yaml 2.14.0 + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + 2.14.0 + @@ -150,6 +155,10 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + ch.obermuhlner big-math diff --git a/src/main/java/com/hubspot/jinjava/JinjavaConfig.java b/src/main/java/com/hubspot/jinjava/JinjavaConfig.java index 9cdee6f85..3cff4787c 100644 --- a/src/main/java/com/hubspot/jinjava/JinjavaConfig.java +++ b/src/main/java/com/hubspot/jinjava/JinjavaConfig.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.google.common.collect.ImmutableSet; import com.hubspot.jinjava.el.JinjavaInterpreterResolver; import com.hubspot.jinjava.el.JinjavaObjectUnwrapper; @@ -158,7 +159,7 @@ private JinjavaConfig(Builder builder) { private ObjectMapper setupObjectMapper(@Nullable ObjectMapper objectMapper) { if (objectMapper == null) { - objectMapper = new ObjectMapper(); + objectMapper = new ObjectMapper().registerModule(new Jdk8Module()); if (legacyOverrides.isUseSnakeCasePropertyNaming()) { objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); } diff --git a/src/main/java/com/hubspot/jinjava/objects/serialization/PyishSerializable.java b/src/main/java/com/hubspot/jinjava/objects/serialization/PyishSerializable.java index b967cb828..da9dd29c5 100644 --- a/src/main/java/com/hubspot/jinjava/objects/serialization/PyishSerializable.java +++ b/src/main/java/com/hubspot/jinjava/objects/serialization/PyishSerializable.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.google.common.annotations.Beta; import com.hubspot.jinjava.interpret.DeferredValueException; import com.hubspot.jinjava.objects.PyWrapper; @@ -19,6 +20,7 @@ public interface PyishSerializable extends PyWrapper { ObjectWriter SELF_WRITER = new ObjectMapper( new JsonFactoryBuilder().quoteChar('\'').build() ) + .registerModule(new Jdk8Module()) .writer(PyishPrettyPrinter.INSTANCE) .with(PyishCharacterEscapes.INSTANCE); diff --git a/src/test/java/com/hubspot/jinjava/util/EagerExpressionResolverTest.java b/src/test/java/com/hubspot/jinjava/util/EagerExpressionResolverTest.java index e634ae0fc..1ee802810 100644 --- a/src/test/java/com/hubspot/jinjava/util/EagerExpressionResolverTest.java +++ b/src/test/java/com/hubspot/jinjava/util/EagerExpressionResolverTest.java @@ -35,6 +35,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicLong; import org.junit.After; @@ -93,6 +94,15 @@ private JinjavaInterpreter getInterpreter(boolean evaluateMapKeys) throws Except this.getClass().getDeclaredMethod("sleeper") ) ); + jinjava + .getGlobalContext() + .registerFunction( + new ELFunctionDefinition( + "", + "optionally", + this.getClass().getDeclaredMethod("optionally", boolean.class) + ) + ); interpreter = new JinjavaInterpreter(jinjava.newInterpreter()); context = interpreter.getContext(); context.put("deferred", DeferredValue.instance()); @@ -124,6 +134,14 @@ public void itResolvesDeferredBoolean() { assertThat(interpreter.resolveELExpression(partiallyResolved, 1)).isEqualTo(true); } + @Test + public void itSerializesNestedOptional() { + assertThat(eagerResolveExpression("[optionally(true)]").toString()) + .isEqualTo("['1'|allow_snake_case]"); + assertThat(eagerResolveExpression("[optionally(false)]").toString()) + .isEqualTo("[null|allow_snake_case]"); + } + @Test public void itResolvesDeferredList() { context.put("foo", "foo_val"); @@ -877,6 +895,10 @@ public static long sleeper() throws InterruptedException { return sleepTime; } + public static Optional optionally(boolean hasValue) { + return Optional.of(hasValue).filter(Boolean::booleanValue).map(ignored -> "1"); + } + private static class Foo { private final String bar;