junit-pioneer: JSON argument source fails with LocalDate property deserialization

For some odd reason I get an exception while deserializing java.time.LocalDate properties:

Failed to convert to type class com.foo.bar.MyClass
java.io.UncheckedIOException: Failed to convert to type class com.foo.bar.MyClass
	at org.junitpioneer.jupiter.json.JacksonNode.toType(JacksonNode.java:51)
	at org.junitpioneer.jupiter.json.JacksonNode.value(JacksonNode.java:85)
...	
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDate` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.foo.bar.MyClass["someDate"])

The JSR-310 Jackson datatype dependency is in the classpath, but upon further inspection the ObjectMapper instance in org.junitpioneer.jupiter.json.JacksonJsonConverter has no registered modules.

Any way to fix this? Or better yet provide a way to customize the used ObjectMapper instance? Right now I’m working around this by using reflection to manually register the module.

Using Gradle 7.1.1 on OpenJDK 11 with classpath.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 21 (15 by maintainers)

Most upvoted comments

Is there any reason why you can’t just expose the object mapper and everyone that needs to configure it grabs the reference? I’m no fan of public static fields, but if the mapper wouldn’t be private, it would at least be possible to grab and configure it. A default Jackson Objectmapper is almost never present in any sufficiently large (eg, more than hello world) project.

But thanks for commenting on this issue @meredrica, it brought it to our attention again. With 2.0 about to be released, this seems like a good time to tackle this issue.

@filiphr, @robtimus: Sorry for not getting back to you - your comments either slipped by unnoticed or I forgot to reply. Thanks for your ideas and readiness to implement.

I re-read this issue and #629 and tried to come up with a minimal solution that focuses on:

  • just Jackson (i.e. no other parsers)
  • only global configuration (i.e. not per test (class))

I just created #704 and #705 - they would give us a relatively simple solution for the immediate issue and an escape hatch for everything more complicated. Once that’s done we can tackle in-between options (e.g. preconfiguring a mapper and passing it to the user for further refinement), per-test(-class) configuration, and other parsers (e.g. GSON).

If we agree on the overall approach (looking at all the JSON users in this thread 👀), I’ll close this issue, so we can work on the other two.

Yes, I understand that it’s not in the default databind dependency. The error message in the issue post already suggests this. 😉

And yes, I have it in classpath. To be clear the tests that use JSON argument source are part of a larger test suite using among many other things Spring Boot JSON starter, that adds all the needed dependencies.

But even if I am missing this dependency like you suggest, how does knowing that (i.e. I have to add it, register the module, etc.) help when I have to use a ton of reflection to get hold of the ObjectMapper instances used by this JUnit extension? The thing I’m talking about -

// non-public class, already a bummer :/
class JacksonJsonConverter implements JsonConverter {

        // need to get this singleton, either directly or using the package private getConverter() method
	private static final JacksonJsonConverter INSTANCE = new JacksonJsonConverter(new ObjectMapper());

        // both have to be changed, since one is a clone of the other with extra settings?
	private final ObjectMapper objectMapper;
	private final ObjectMapper lenientObjectMapper;

Hi @virtual-machinist,

thx for reaching out – we will look into this.