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

Remove Paranamer usage where possible #449

Closed
zhao-zihao opened this issue Jun 2, 2020 · 11 comments
Closed

Remove Paranamer usage where possible #449

zhao-zihao opened this issue Jun 2, 2020 · 11 comments
Assignees
Labels

Comments

@zhao-zihao
Copy link

zhao-zihao commented Jun 2, 2020

I have a project based on scala 2.13, JDK 8, and jackson-module-scala 2.11.0. Recently we upgrade to JDK 11.

Then jackson-module-scala throw an IndexOutOfBoundsException from BytecodeReadingParanamer class.
I noticed that the BeanIntrospector.scala of the jackson-module-scala import the problematic com.thoughtworks.paranamer.BytecodeReadingParanamer, which hasn't get updated since 4 years ago and it only support JDK 8.

@pjfanning
Copy link
Member

pjfanning commented Jun 2, 2020

jackson-module-scala unit tests run ok on OpenJDK 11 - see https://travis-ci.org/github/FasterXML/jackson-module-scala/builds/693266062 - if you provide a reproducible test case, we can look at it

@zhao-zihao
Copy link
Author

zhao-zihao commented Jun 8, 2020

@pjfanning Thanks for your help! I solved the issue!

We have a class like this:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ExampleProperty {
    @JsonProperty("name") private String name = null;
    @JsonProperty("value") private String value = null;

    @JsonCreator
    public ExampleProperty(String name, String value) {
        this.name = name;
        this.value = value;
        validate();
    }

The above code worked in JDK 8 but failed in JDK 11.

To make it work, I removed the ScalaAnnotationIntrospectorModule of DefaultScalaModule, which uses the paranamer library(supports JDK 8) to get parameter names using Java reflection. To solve this, I added @JsonProperty annotation to arguments. And the code would be like this:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ExampleProperty {
    @JsonProperty("name") private String name = null;
    @JsonProperty("value") private String value = null;

    @JsonCreator
    public ExampleProperty(@JsonProperty("name") String name, @JsonProperty("value") String value) {
        this.name = name;
        this.value = value;
        validate();
    }

@pjfanning
Copy link
Member

@zhao-zihao that code you provided is plain java and not scala - do you use scala at all and if not, can you just remove the jackson-module-scala dependency?

@pjfanning
Copy link
Member

pjfanning commented Jun 8, 2020

@cowtowncoder it's easy to drop paranamer usage in jackson-module-scala if we replace it with Java8 specific code. With Jackson 3, is it the intention to drop support for Java 7 and below?

https://stackoverflow.com/questions/21455403/how-to-get-method-parameter-names-in-java-8-using-reflection

@cowtowncoder
Copy link
Member

@pjfanning Yes, Jackson 3.0 is Java8+ only at this point and earlier versions will not be supported. There may even be question of requiring some later JDK version, but JDK8 for sure.

In addition, every module can decided if they might want to go Java 8 with 2.x as well: some modules do that (jackson-module-kotlin requires Java 8, and I think some datatype modules might as well). So it might make sense to consider going Java 8 with Scala module 2.12, for example?

@pjfanning
Copy link
Member

Thanks @cowtowncoder, I would favour dropping Java 7 support in jackson-module-scala 2.12.0.

I might even try to remove the dependency on jackson-module-paranamer in jackson-module-scala 2.12.0.

@zhao-zihao
Copy link
Author

zhao-zihao commented Jun 8, 2020

@zhao-zihao that code you provided is plain java and not scala - do you use scala at all and if not, can you just remove the jackson-module-scala dependency?

@pjfanning
Yes. I am using the scala Play Framework 2.8.2.
The app will give me an error like the following if I remove the jackson-module-scala completely.

[info]   com.**.exception.ExampleException: Invalid data for JSON processing. com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.HashSet<com.**.ShowExpressionAsType>` out of START_OBJECT token

Then I add back the IterableModule to deserialize a HashSet parameter in HTTP Request.
ExampleIterableModule.scala:

import com.fasterxml.jackson.module.scala.{ IterableModule}
class ExampleIterableModule extends IterableModule {}

JsonAPISerizlizer.java:

new ObjectMapper().registerModule(new ExampleIterableModule())

@pjfanning pjfanning changed the title Does jackson-module-scala 2.11.0 support JDK 11? Remove Paranamer usage where possible Jun 9, 2020
@pjfanning pjfanning self-assigned this Jun 9, 2020
@pjfanning pjfanning added the 2.12 label Jun 9, 2020
@pjfanning
Copy link
Member

So, in jackson-module-scala 2.12.0-SNAPSHOT, I have dropped java 7 support (which only affects scala 2.10/2.11 as scala 2.12/2.13 already only supported java 8). I have removed the dependency on jackson-module-paranamer.

scala 2.10/2.11 builds still need paranamer as these scala versions build java classes without full java8 support.

@cowtowncoder
Copy link
Member

Note: Scala 2.10 support was dropped from Jackson 2.12 so Paranamer dependency only exists for Scala 2.11.

@afsilvasantos
Copy link

I am having the original problem right now. My situation is a bit different though. The error started appearing in the Unit Tests after upgrading Play Framework from version 2.7.9 to 2.8.17.
As of before the upgrade, I am using Scala 2.13.8 version.

This is the unit test method that fails:

    @Before
    public void setup() {
        AfvPartyLinkRequest dto = random(AfvPartyLinkRequest.class);
        request = fakeRequest().bodyJson(Json.toJson(dto)).build();

        when(userMock.hasRole(ACCOUNT_MANAGER)).thenReturn(true);
    }

Anywhere there is a call of Json.toJson(Object), it throws the index out of bounds exception like this:

[error] Test services.linking.FundPartyLinkerTest.testSuccessfullyLinkEntities failed: java.lang.RuntimeException: java.lang.ArrayIndexOutOfBoundsException: Index 29743 out of bounds for length 140, took 0.161 sec
[error]     at play.libs.Json.toJson(Json.java:94)
[error]     at services.linking.FundPartyLinkerTest.testSuccessfullyLinkEntities(FundPartyLinkerTest.java:91)
[error]     at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]     at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]     at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]     at java.lang.reflect.Method.invoke(Method.java:566)
[error]     ...
[error] Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 29743 out of bounds for length 140
[error]     at com.fasterxml.jackson.module.paranamer.shaded.BytecodeReadingParanamer$ClassReader.accept(BytecodeReadingParanamer.java:577)
[error]     at com.fasterxml.jackson.module.paranamer.shaded.BytecodeReadingParanamer$ClassReader.access$200(BytecodeReadingParanamer.java:338)
[error]     at com.fasterxml.jackson.module.paranamer.shaded.BytecodeReadingParanamer.lookupParameterNames(BytecodeReadingParanamer.java:103)
[error]     at com.fasterxml.jackson.module.paranamer.shaded.CachingParanamer.lookupParameterNames(CachingParanamer.java:90)
[error]     at com.fasterxml.jackson.module.paranamer.SerializableParanamer.findParameterName(SerializableParanamer.java:50)
[error]     at com.fasterxml.jackson.module.paranamer.ParanamerAnnotationIntrospector.findImplicitPropertyName(ParanamerAnnotationIntrospector.java:67)
[error]     at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findImplicitPropertyName(AnnotationIntrospectorPair.java:490)
[error]     at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findImplicitPropertyName(AnnotationIntrospectorPair.java:489)
[error]     at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:512)
[error]     at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:500)
[error]     at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:327)
[error]     at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getJsonValueAccessor(POJOPropertiesCollector.java:203)
[error]     at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findJsonValueAccessor(BasicBeanDescription.java:252)
[error]     at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerByAnnotations(BasicSerializerFactory.java:396)
[error]     at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:216)
[error]     at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:165)
[error]     at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1474)
[error]     at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1422)
[error]     at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:521)
[error]     at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:799)
[error]     at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:308)
[error]     at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3058)
[error]     at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:3227)
[error]     at play.libs.Json.toJson(Json.java:92)

How can I overcome this? I checked and all jackson dependencies are on 2.11.4 version, which is the direct jackson dependency version for Play 2.8.17

@pjfanning
Copy link
Member

@afsilvasantos where is jackson-module-scala in your stacktrace? You seem to be using play-json and play-json does not use jackson-module-scala - it only used plain jackson-databind.

Please do not raise this as a jackson-databind issue either - the Jackson team have limited time and will not want to debug Play for you. A Jackson only test case is what is needed if you expect anyone from Jackson team to debug your issue for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants