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

JAXB @XmlValue deserializing not working with records #559

Open
micopiira opened this issue Dec 1, 2022 · 6 comments
Open

JAXB @XmlValue deserializing not working with records #559

micopiira opened this issue Dec 1, 2022 · 6 comments
Labels
2.15 For issues planned for 2.15 has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue

Comments

@micopiira
Copy link

micopiira commented Dec 1, 2022

@XmlAttribute and @XmlElement seem to work fine with records, and @XmlValue seems to work when serializing but deserializing fails with java.lang.IllegalAccessException

public class Main {

    public record TestObject (
            @XmlValue
            String name,
            @XmlAttribute
            int age) {}

    public static void main(String[] args) throws JsonProcessingException {
        XmlMapper xmlMapper = new XmlMapper();
        JakartaXmlBindAnnotationModule module = new JakartaXmlBindAnnotationModule();
        xmlMapper.registerModule(module);
        TestObject testObject = new TestObject("foo", 12);
        String xml = xmlMapper.writeValueAsString(testObject);
        TestObject testObject1 = xmlMapper.readValue(xml, TestObject.class);
    }
}

stacktrace:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not set final java.lang.String field org.example.Main$TestObject.name to java.lang.String
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:276)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:627)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:615)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:638)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.set(FieldProperty.java:193)
	at com.fasterxml.jackson.databind.deser.impl.PropertyValue$Regular.assign(PropertyValue.java:60)
	at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.build(PropertyBasedCreator.java:211)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:519)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1405)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
	at com.fasterxml.jackson.dataformat.xml.deser.XmlTextDeserializer.deserialize(XmlTextDeserializer.java:96)
	at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(XmlDeserializationContext.java:91)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4730)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3677)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3645)
	at org.example.Main.main(Main.java:25)
Caused by: java.lang.IllegalAccessException: Can not set final java.lang.String field org.example.Main$TestObject.name to java.lang.String
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)
	at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.set(UnsafeQualifiedObjectFieldAccessorImpl.java:79)
	at java.base/java.lang.reflect.Field.set(Field.java:799)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.set(FieldProperty.java:190)
	... 12 more

I'm using java 17 and jackson 2.14.1

@cowtowncoder
Copy link
Member

I suspect this is related to general issues with annotation merging, records, to be resolved in jackson-databind in (I hope) nearish future (for 2.15).

One challenge here is that it could also be related to XML module handling. It would be great if the issue could be reproduced with Jackson's own annotations, only because then issue could be moved to jackson-dataformat-xml; test in this repo cannot depend on XML module.

Actually, I think I'll move this to XML module repo since it can depend on JAXB/Jakarta-Bind annotations but not vice versa.

@cowtowncoder cowtowncoder transferred this issue from FasterXML/jackson-modules-base Dec 1, 2022
@cowtowncoder cowtowncoder added has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue 2.15 For issues planned for 2.15 labels Dec 1, 2022
@cowtowncoder
Copy link
Member

Come to think of it, challenging to test even here wrt Records being JDK 15+ feature. Oh well.

@toellrich
Copy link

I have a similar problem when adding the attribute name to @XmlElement. Using the same main-Method as above, the following works:

public record TestObject(
    @XmlElement String name,
    @XmlAttribute int age) {
 }

But this does not:

public record TestObject(
    @XmlElement(name = "Name") String name,
    @XmlAttribute int age) {
}

Stacktrace:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not set final java.lang.String field org.example.Main$TestObject.name to java.lang.String
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:276)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:627)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:615)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:638)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.set(FieldProperty.java:193)
	at com.fasterxml.jackson.databind.deser.impl.PropertyValue$Regular.assign(PropertyValue.java:60)
	at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.build(PropertyBasedCreator.java:211)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:519)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1405)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
	at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(XmlDeserializationContext.java:91)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4730)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3677)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3645)
	at org.example.Main.main(Main.java:28)
Caused by: java.lang.IllegalAccessException: Can not set final java.lang.String field org.example.Main$TestObject.name to java.lang.String
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
	at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)
	at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.set(UnsafeQualifiedObjectFieldAccessorImpl.java:79)
	at java.base/java.lang.reflect.Field.set(Field.java:799)
	at com.fasterxml.jackson.databind.deser.impl.FieldProperty.set(FieldProperty.java:190)
	... 11 more

I'm using java 17 and jackson 2.14.2

@cowtowncoder
Copy link
Member

I would recommend trying this against new 2.15.0-rc1 -- 2.15 branch has lots of improvements to handling of Record types.

@micopiira
Copy link
Author

@cowtowncoder Hey, I tried 2.15.0-rc1.

I can confirm that the code posted by @toellrich does indeed work with 2.15.0-rc1. However there seems to still be problems with the jakarta.xml.bind.annotation.XmlValue annotation.

With the code in the first post, serialization still works but deserializationfails with error:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "" (class com.example.demo.Test$TestObject), not marked as ignorable (2 known properties: "name", "age"])
 at [Source: (StringReader); line: 1, column: 38] (through reference chain: com.example.demo.Test$TestObject[""])
	at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1138)
	at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:2224)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1709)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperties(BeanDeserializerBase.java:1659)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:544)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
	at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(XmlDeserializationContext.java:91)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4730)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3677)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3645)

@cowtowncoder
Copy link
Member

Ok thank you for checking @micopiira. At least things get bit further.
Reference to empty String is because value marked with @XmlValue does not have actual property name matched from XML so it needs sort of placeholder.
Won't really help resolve the issue but may be interesting to know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.15 For issues planned for 2.15 has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue
Projects
None yet
Development

No branches or pull requests

3 participants