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

Fail to deserialize local Records #2758

Closed
DasBrain opened this issue Jun 11, 2020 · 5 comments
Closed

Fail to deserialize local Records #2758

DasBrain opened this issue Jun 11, 2020 · 5 comments
Labels
JDK11 Features that need JDK11 (and/or support JDK11)
Milestone

Comments

@DasBrain
Copy link

DasBrain commented Jun 11, 2020

Reproducer:

record NestedRecord(@JsonProperty("foo")String foo) {
    @JsonCreator
    public NestedRecord(@JsonProperty("foo") String foo) {
        this.foo = foo;
    }
}

public static void main(String[] args) throws Throwable {
    String json = "{\"foo\":\"bar\"}";
    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.readValue(json, NestedRecord.class));
    
    
    record LocalRecord(@JsonProperty("foo") String foo) {
        @JsonCreator 
        public LocalRecord(@JsonProperty("foo") String foo) {
            this.foo = foo;
        }
    }
    System.out.println(mapper.readValue(json, LocalRecord.class));
}

Jackson fails with the following error message:

NestedRecord[foo=bar]
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Cannot deserialize Class test.TestMain$1LocalRecord (of type local/anonymous) as a Bean
 at [Source: (String)"{"foo":"bar"}"; line: 1, column: 1]
    at [email protected]/com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:309)
    at [email protected]/com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:268)
    at [email protected]/com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at [email protected]/com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at [email protected]/com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:491)
    at [email protected]/com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4669)
    at [email protected]/com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4478)
    at [email protected]/com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434)
    at [email protected]/com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3402)
    at test/.test.TestMain.main(TestMain.java:37)
Caused by: java.lang.IllegalArgumentException: Cannot deserialize Class test.TestMain$1LocalRecord (of type local/anonymous) as a Bean
    at [email protected]/com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.isPotentialBeanType(BeanDeserializerFactory.java:883)
    at [email protected]/com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:137)
    at [email protected]/com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:414)
    at [email protected]/com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
    at [email protected]/com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    ... 8 more

It seems to identify the local record as a local class, which is incorrect according to JLS § 14.3:

... A local record is not a local class.

@cowtowncoder cowtowncoder added the JDK11 Features that need JDK11 (and/or support JDK11) label Jun 12, 2020
@cowtowncoder
Copy link
Member

cowtowncoder commented Jun 12, 2020

Ok. Not quite sure what would be usable heuristics on JDK 7 to figure out this specific case: inner classes that are not static are considered problematic (since they expect "hidden this parameter" to be passed). Since Jackson can not use JDK functionality for detecting Record identifying aspects, it would have to be based on something else that differs between records and non-static inner classes.

As a work-around, is it possible to mark records as static (even if it makes no difference).

@DasBrain
Copy link
Author

DasBrain commented Jun 12, 2020

Records are implicitly static. So Modifier.isStatic(type.getModifiers()) returns true on them.
This is not true for local classes, as they can not be static (yet).

In com.fasterxml.jackson.databind.util.ClassUtil, change Line 130 to:

if (!Modifier.isStatic(type.getModifiers()) && hasEnclosingMethod(type)) {

Also note that Jackson CAN deserialize a record declared inside a class, it just can not deserialize local records.

@cowtowncoder
Copy link
Member

cowtowncoder commented Jun 15, 2020

Makes sense wrt static, was just guessing on what might be happening based on symptoms (although exception message in desc should actually have pointed me in right direction).

Quick question: line 130 on which branch? Or more importantly, in which method? isNonStaticInnerClass? If so, that'd make sense, check was probably meant to check for enclosing method

@DasBrain
Copy link
Author

master branch. I did link the corresponding line.

@cowtowncoder
Copy link
Member

Thank you.

@cowtowncoder cowtowncoder removed the 2.10 label Jun 24, 2020
@cowtowncoder cowtowncoder added this to the 2.11.1 milestone Jun 24, 2020
@cowtowncoder cowtowncoder changed the title Jackson-Databind fails to deserialize local records Fail to deserialize local Records Jun 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JDK11 Features that need JDK11 (and/or support JDK11)
Projects
None yet
Development

No branches or pull requests

2 participants