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

ClassUtil fails with java.lang.reflect.InaccessibleObjectException trying to setAccessible on OptionalInt with JDK 17+ #4082

Closed
1 task done
jaikiran opened this issue Aug 18, 2023 · 6 comments

Comments

@jaikiran
Copy link

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

Please consider the following trivial Java code:

package org.myapp;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.OptionalInt;

public class Main {
    public static void main(final String[] args) throws Exception {
        final ObjectMapper objectMapper = new ObjectMapper();
        final String json = "{ }"; // empty
        final Data data = objectMapper.readValue(json, Data.class);
        System.out.println("Read data: " + data);
    }

    public static class Data {
        private OptionalInt value;

        public Data() {

        }

        public void setValue(OptionalInt i) {
            this.value = i;
        }


        public OptionalInt getValue() {
            return this.value;
        }

        @Override
        public String toString() {
            return "Data[value=" + this.value + "]";
        }
    }
}

When using jackson-databind 2.15.2 and Java version 17 and running this program, it results in:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make private java.util.OptionalInt() accessible: module java.base does not "opens java.util" to unnamed module @4cf328c3
    at java.lang.reflect.AccessibleObject.throwInaccessibleObjectException (AccessibleObject.java:387)
    at java.lang.reflect.AccessibleObject.checkCanSetAccessible (AccessibleObject.java:363)
    at java.lang.reflect.AccessibleObject.checkCanSetAccessible (AccessibleObject.java:311)
    at java.lang.reflect.Constructor.checkCanSetAccessible (Constructor.java:192)
    at java.lang.reflect.Constructor.setAccessible (Constructor.java:185)
    at com.fasterxml.jackson.databind.util.ClassUtil.checkAndFixAccess (ClassUtil.java:995)
    at com.fasterxml.jackson.databind.deser.impl.CreatorCollector._fixAccess (CreatorCollector.java:278)
    at com.fasterxml.jackson.databind.deser.impl.CreatorCollector.setDefaultCreator (CreatorCollector.java:130)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addExplicitConstructorCreators (BasicDeserializerFactory.java:438)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator (BasicDeserializerFactory.java:293)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator (BasicDeserializerFactory.java:222)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer (BeanDeserializerFactory.java:262)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer (BeanDeserializerFactory.java:151)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2 (DeserializerCache.java:415)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer (DeserializerCache.java:350)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2 (DeserializerCache.java:264)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer (DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer (DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findNonContextualValueDeserializer (DeserializationContext.java:644)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve (BeanDeserializerBase.java:539)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2 (DeserializerCache.java:294)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer (DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer (DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer (DeserializationContext.java:654)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer (ObjectMapper.java:4956)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose (ObjectMapper.java:4826)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue (ObjectMapper.java:3772)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue (ObjectMapper.java:3740)
    at org.myapp.Main.main (Main.java:10)

So com.fasterxml.jackson.databind.util.ClassUtil is trying to setAccessible() on the private constructor of a JDK class java.util.OptionalInt. One way to solve this issue is to configure the ObjectMapper instance as follows:

objectMapper.configure(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);

However, while looking at the code in com.fasterxml.jackson.databind.util.ClassUtil I noticed that there's a specific logic which tries to not setAccessible() on JDK internal classes here https://github.com/FasterXML/jackson-databind/blob/jackson-databind-2.15.2/src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java#L994 which looks like:

if (!isPublic || (evenIfAlreadyPublic && !isJDKClass(declaringClass))) {
      ao.setAccessible(true);
  }

Should that !isJDKClass(declaringClass) be perhaps applied even when evenIfAlreadyPublic is false? Something like:

if (!isJDKClass(declaringClass) && (!isPublic || evenIfAlreadyPublic)) {
      ao.setAccessible(true);
  }

That way, it won't try to access the internal JDK classes and run into these exceptions on Java 17+?

Version Information

2.15.2

Reproduction

No response

Expected behavior

No response

Additional context

No response

@jaikiran jaikiran added the to-evaluate Issue that has been received but not yet evaluated label Aug 18, 2023
@pjfanning
Copy link
Member

If you want to use OptionalInt, you should register this module -> https://github.com/FasterXML/jackson-modules-java8

If you continue to get issues like this, you might need to use the Java command line option --add-opens, eg --add-opens java.base/java.util=ALL-UNNAMED"

@cowtowncoder cowtowncoder changed the title com.fasterxml.jackson.databind.util.ClassUtil fails with java.lang.reflect.InaccessibleObjectException trying to setAccessible on JDK class on Java 17+ ClassUtil fails with java.lang.reflect.InaccessibleObjectException trying to setAccessible on OptionalInt with JDK 17+ Aug 19, 2023
@cowtowncoder cowtowncoder removed the to-evaluate Issue that has been received but not yet evaluated label Aug 19, 2023
@cowtowncoder
Copy link
Member

@pjfanning is correct in pointing out need for JDK8 types module.

But I think we could also add block in BeanUtil for these types (similar to Java 8 Date/Time, Joda types) in absence of module-provided (de)serializers.

@jaikiran
Copy link
Author

Hello Tatu and @pjfanning, thank you for looking into this.

If you want to use OptionalInt, you should register this module

The use of OptionalInt in this reproducer was just an example where the ClassUtil ended up trying to setAccessible on JDK members (in this case a private constructor). I was hoping this could be avoided out of the box, if feasible, since the code in that if block seemed to indicate that there are mechanisms in place (like isJDKClass) to try and avoid similar cases.

@jaikiran
Copy link
Author

If you want to use OptionalInt, you should register this module -> https://github.com/FasterXML/jackson-modules-java8

I gave this a quick try in that trivial reproducer by registering this module as explained in https://github.com/FasterXML/jackson-modules-java8/tree/2.15/datatypes#readme and that does indeed help. I no longer see any reflection access related exceptions being thrown in Java 17+, which is understandable because looking at the implementation in the jackson-datatype-jdk8 I don't see any reflection usage. Thank you for pointing to that module.

So I think it's now a matter of deciding whether in the absence of this module registration, would it be possible to prevent calling setAccessible() on the JDK classes. I don't have much experience with jackson, so I can't say if that's a feasible or reasonable thing to do.

@JooHyukKim
Copy link
Member

JooHyukKim commented Aug 19, 2023

But I think we could also add block in BeanUtil for these types (similar to Java 8 Date/Time, Joda types) in absence of module-provided (de)serializers.

If this means adding if-block in...

public static String checkUnsupportedType(JavaType type) {

... this method to provide meaningful exception message, +1️⃣.

EDITED : I will come back later and work on this if it has not been done yet.

@cowtowncoder
Copy link
Member

I am working on a PoC solution here.

paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Nov 27, 2023
Jackson adapted handling for Optional serialization providing a custom
exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.

See
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Nov 29, 2023
Jackson adapted handling for Optional serialization providing a custom
exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.

See
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Nov 29, 2023
Jackson adapted handling for Optional serialization providing a custom
exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.

See
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Dec 1, 2023
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Dec 1, 2023
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Dec 4, 2023
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Dec 4, 2023
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c

354734
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Dec 5, 2023
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c

354734
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Dec 6, 2023
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c

354734
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Jan 11, 2024
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c

354734, 371286
paolobazzi added a commit to eclipse-scout/scout.rt that referenced this issue Jan 11, 2024
(1) Jackson adapted handling for Optional serialization providing a
custom exception message if Optional is being serialized. Scout does not
support serialization of Java Optional, therefore adapt test case.
See also:
FasterXML/jackson-databind#4082
FasterXML/jackson-databind@d7e77c3

(2) Jackson adapted handling for untyped deserialization of floating
point numbers. Former implementations (before 2.15) deserialized
floating point numbers within lists as BigDecimal. Since issue 903 and
3751 numbers are deserialized into the smalles possible Java data type
(same behavior as plain numbers not within a JSON list element).
Therefore Scout DoCollectionDeserializer was adapted identically to
DoEntityDeserializer to enforce using BigDecimal for unknown (raw)
number deserialization.

See also:
FasterXML/jackson-core#903
FasterXML/jackson-core@4c957e3
and
FasterXML/jackson-databind#3751
FasterXML/jackson-databind@23ea48c

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

No branches or pull requests

4 participants