Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Registration of jackson-datatype-jsr310 not working in Jackson 2.12.0 #2983

Closed
retrodaredevil opened this issue Dec 13, 2020 · 18 comments
Closed
Labels
to-evaluate Issue that has been received but not yet evaluated

Comments

@retrodaredevil
Copy link

retrodaredevil commented Dec 13, 2020

Describe the bug
On 2.12.0 (2.11.3 doesn't have this bug), findAndRegisterModules does not work for com.fasterxml.jackson.datatype:jackson-datatype-jsr310.

Exception in thread "main" java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.Duration` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
 at [Source: (String)"{ "duration": "PT5M" }"; line: 1, column: 15] (through reference chain: me.retrodaredevil.solarthing.program.SolarMain$TestObject["duration"])
        at me.retrodaredevil.solarthing.program.SolarMain.doMain(SolarMain.java:227)
        at me.retrodaredevil.solarthing.program.SolarMain.main(SolarMain.java:275)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.Duration` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
 at [Source: (String)"{ "duration": "PT5M" }"; line: 1, column: 15] (through reference chain: me.retrodaredevil.solarthing.program.SolarMain$TestObject["duration"])
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
        at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1766)
        at com.fasterxml.jackson.databind.deser.impl.UnsupportedTypeDeserializer.deserialize(UnsupportedTypeDeserializer.java:36)
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:565)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:449)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1390)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)
        at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4591)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3546)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3514)

Version information
2.12.0 on Java 11

To Reproduce

private static class TestObject {
	private TestObject(@JsonProperty("duration") Duration duration) {

	}
}

ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
mapper.readValue("{ \"duration\": \"PT5M\" }", TestObject.class);

Expected behavior
It should find the module and not throw the error above.

Additional context
I tried putting my code in a JUnit5 test, and it passed perfectly, so this bug isn't something that can be detected by unit tests. I'm using the shadow gradle plugin to compile my code into a fat jar, so something changed between 2.11 and 2.12 that causes this.

Also, adding the line mapper.registerModule(new JavaTimeModule()); fixes it, so I can guarantee that it exists on my classpath.

I wish I had some more info on why this is happening, but seeing how I can't reproduce this in a unit test, I don't really have any idea what the problem is.

@retrodaredevil retrodaredevil added the to-evaluate Issue that has been received but not yet evaluated label Dec 13, 2020
@retrodaredevil
Copy link
Author

Some of my assumptions above were wrong, I fixed this by reverting my api "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3" jackson-datatype-jsr310 dependency to 2.11.3, so maybe something changed there that makes it so it cannot be detected?

@anirudh1122399
Copy link

@retrodaredevil so, is this fixed or did you raise this to find out and confirm if this was a bug or not? I do not understand the label "to-evaluate", could you elaborate please?

@cowtowncoder
Copy link
Member

cowtowncoder commented Dec 13, 2020

@anirudh1122399 "to-evaluate" is automatically added by github issue template -- it's for my use, to help remember issues I have had a decent look at.

@retrodaredevil Hmmh. I am not aware of change that should prevent auto-registration, and definitely such change in behavior is not intentional.

@cowtowncoder
Copy link
Member

I think the first step here would be to add a test in:

https://github.com/FasterXML/jackson-integration-tests/

since that can have cross-module dependencies and operate on jars (java 8 modules' unit tests could otherwise test it but it would run against compiled classes, not jar).

I hope to have time to look into this in near future, but if anyone else has time for test reproduction that'd be great.
It would also be good to know if this affects other modules or not.

@cowtowncoder
Copy link
Member

After trying this out with a manual test, I do not see an immediate problem with auto-registration: parameter names module seems to located accurately and registered.
Perhaps I am reading comments above wrong and auto-registration is not the problem? Will try to reproduce with explicit test.

@cowtowncoder cowtowncoder changed the title findAndRegisterModules not working in Jackson 2.12.0 Registration of jackson-datatype-jsr310 not working in Jackson 2.12.0 Dec 14, 2020
@cowtowncoder
Copy link
Member

cowtowncoder commented Dec 14, 2020

Also failed to reproduce with test case itself, both by registering specific module and by using findAndRegisterModules().

At this point I am unfortunately unable to reproduce the problem unfortunately and have no idea on what might be causing it.

@retrodaredevil
Copy link
Author

If I find the time, I'll try creating a project that creates a jar file with this problem since I can't reproduce it in a simple unit test, either.

Like I said, if I use these dependencies:

api "com.fasterxml.jackson.core:jackson-core:2.12.0"
api "com.fasterxml.jackson.core:jackson-annotations:2.12.0"
api "com.fasterxml.jackson.core:jackson-databind:2.12.0"
api "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.3"

It does work. But if I use

api "com.fasterxml.jackson.core:jackson-core:2.12.0"
api "com.fasterxml.jackson.core:jackson-annotations:2.12.0"
api "com.fasterxml.jackson.core:jackson-databind:2.12.0"
api "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.0" // change here

It does not work.

There's also a possibility that this error doesn't come up if you're using Java 8 (I tested with Java 11).

It's possible I'll find the time sometime in the next day, or next few days. I don't really have an idea right now.

@cowtowncoder
Copy link
Member

@retrodaredevil Thanks. I'll get whatever you can find out. Depending on how easy/difficult it is to do, note that there is also method ObjectMapper.findModules() that can give a list on modules that would be found, but not register; that might allow comparisons to see whether problem is with:

  1. Module not being found at all
  2. Registration failing somehow (although where is the exception?)
  3. Something else (registration not taking effect)

@retrodaredevil
Copy link
Author

Ok, so when I first made an empty project and started to add jackson dependencies, I was unable to reproduce this, then I added my mattermost4j dependencies, which also depends on a bunch of other stuff, and that got the same result as my much larger project.

Here's the repo: https://github.com/retrodaredevil/jackson-test

To reproduce, run ./compile_and_move.sh (a simple script to compile using shadow), then run java -jar jackson-test.jar. That will give you an error. If you go into client's build.gradle and remove the mattermost4j dependency, this will magically start working. To make this start working, you can also use 2.11.3 as the jackson version as mentioned above.

You'll notice that it will find the JaxbAnnotationModule module instead of the JavaTimeModule, which is from some dependency in mattermost4j. You'll probably have to run ./gradlew client:dependencies to see what's going on, but I mean, all the correct jackson dependencies are there, so I don't know why this is happening.

@cowtowncoder
Copy link
Member

cowtowncoder commented Dec 17, 2020

For whatever reason, this seems to pass for me, without any changes (just clone the project), using JDK 11.0.8.

Output is:

Result of ObjectMapper.findModules():
[com.fasterxml.jackson.datatype.jsr310.JavaTimeModule@45018215]
PT5M

But I think I have an idea of what could be the problem.

Looking at test jar I notice that it is simply flattening contents of all META-INF directories: this won't work for a few reasons, specifically since full file paths are not unique: and specifically wrt SPI declaration for Jackson modules, all jars will have

META-INF/services/com.fasterxml.jackson.databind.Module

of which only one survives, and order is probably not stable.
Same problem will affect module-info.class too.

Why this used to work may be due to JSR310Module having "won" the race?

@retrodaredevil
Copy link
Author

Oh that makes sense. Yeah it was weird to me that when the JavaTimeModule showed up the JaxbAnnotationModule did not. I'll have to look into how to make shadow create a jar file with the correct META-INF. If you have any ideas, let me know as I'm not the best at fixing issues like this for jar files. Hopefully shadow has a simple config option that will fix this, but I don't really know how it works.

I guess I'll go ahead and close this issue since it's not really a problem with Jackson itself.

@cowtowncoder
Copy link
Member

@retrodaredevil Yeah I am not 100% sure how META-INF resource metadata entries should be combined unfortunately. I would think tools need to be able to do that since it is quite common way to include SPI configuration metadata; shade plug-in f.ex should be able to handle it, but I do not really know details.

@retrodaredevil
Copy link
Author

For future reference for those using the shadow plugin to build their jars, just add mergeServiceFiles() to your shadowJar { } config. https://stackoverflow.com/questions/32887966/shadow-plugin-gradle-what-does-mergeservicefiles-do#32902274

That was an incredibly simple fix.

@cowtowncoder
Copy link
Member

@retrodaredevil that makes sense: since the naming of SPI files must be identical, it should make sense that contents can typically be simply concatenated from multiple sources. Thank you for confirming.

@bvn13
Copy link

bvn13 commented Mar 21, 2022

Adding dependency

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>

helps me to solve the issue.

@GregThesus
Copy link

@bvn13 this worked for me, thanks.

@jbauerrfid
Copy link

It works for me with this code:

add to POM:

    <properties>
        <com.fasterxml.jackson.version>2.13.1</com.fasterxml.jackson.version>
    </properties>

            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${com.fasterxml.jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.datatype</groupId>
                <artifactId>jackson-datatype-jsr310</artifactId>
                <version>${com.fasterxml.jackson.version}</version>
            </dependency>

adjust the version as needed :-)

then create the ObjectMapper like this in Java:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;


            ObjectMapper mapper = JsonMapper.builder()
                    .addModule(new JavaTimeModule())
                    .build();

when it does not load the module automatically, we simply force it to be happy

@jamesmehorter
Copy link

Related and possibly helpful for someone

With the following in my gradle.build.kts...

api("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")

...the resulting published POM for my build does not include jackson-datatype-jsr310 as a dependency.

However, if I define the version it is present in the published POM

api("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
to-evaluate Issue that has been received but not yet evaluated
Projects
None yet
Development

No branches or pull requests

7 participants