Skip to content
This repository has been archived by the owner on Jan 22, 2019. It is now read-only.

Jackson marshall ignores @XmlAttribute required = true for a “public final static int” #60

Closed
redblue36 opened this issue Aug 16, 2016 · 7 comments

Comments

@redblue36
Copy link

redblue36 commented Aug 16, 2016

Experiencing a condition where Jackson's JAXB Annotation-aware marshaling to JSON seems to ignore a "public final static int" annotated using @XmlAttribute(name = "theVersion", required = true) in the Java object. Thought initially that GitHub Issue #47 applied to this problem but doesn't appear to resolve.

Everything else in this Java object marshals out just fine.

Wondering if there is an object mapper config or something else I'm missing.

Additional information:

  • Using Jackson 2.8.1 associated dependencies pulled via mvn using <dependency org="com.fasterxml.j‌​ackson.module" name="jackson-module‌​-jaxb-annotations" rev="2.8.1"
  • Using XML Schema to define a fixed attribute like so: <xs:attribute name="theVersion" type="xs:int" use="required" fixed="1" />
  • Used JAXB to generate Java annotated objects using this bindings config <jaxb:globalBindings fixedAttributeAsConstantProperty="true">
  • Using that bindings config, JAXB generated java code like...
    @XmlAttribute(name = "theVersion", required = true) public final static int THE_VERSION = 1;
  • Observation: JAXB doesn't generate a getter for this public final static int.

The Jackson Object Mapper config options using at the moment =
SerializationFeature WRAP_ROOT_VALUE true
SerializationFeature WRITE_DATES_AS_TIMESTAMPS false
SerializationFeature INDENT_OUTPUT true

@cowtowncoder
Copy link
Member

@redblue36 it would be great to have the example class and simple usage here: while explanation is useful, it is easy to get a particular detail wrong.

Just to make sure XML Schema is not used at all; Jackson (and modules) operates only on actual POJO classes.

@redblue36
Copy link
Author

redblue36 commented Aug 16, 2016

@cowtowncoder I've attached a sample JAXB class that was generated from an xml schema -- it represents the aspects of the issue noted in the ticket. It is this JAXB annotated object trying to marshal to JSON text using Jackson.

Marshaling code =

        AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(
                jacksonObjectMapper.getTypeFactory());
        jacksonObjectMapper.setAnnotationIntrospector(introspector);

        jacksonObjectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE,
                true);
        jacksonObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
                true);
        jacksonObjectMapper.configure(SerializationFeature.INDENT_OUTPUT,
                true);      

        // marshal JAXB java object to JSON text using Jackson
        String result = jacksonObjectMapper.writeValueAsString(msg);
                System.out.println(result);

This code produces this..

{
  "messageARequest" : {
    "description" : "the description here"
  }
}

The result expected =

{
  "messageARequest" : {
    "description" : "the description here"
    "theVersion" : 1
  }
}

MessageARequest.java.txt

@cowtowncoder
Copy link
Member

package objects.hellotest;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "description"
})
@XmlRootElement(name = "messageARequest")
public class MessageARequest {

    protected String description;

    @XmlAttribute(name = "theVersion", required = true)
    public final static int THE_VERSION = 1;

    public String getDescription() {
        return description;
    }

    public void setDescription(String value) {
        this.description = value;
    }
}

@cowtowncoder
Copy link
Member

@redblue36 Ok, should have paid attention to the title. So: static fields are never included in serialization, no matter what. They are not part of value instances so they are dropped by design.
Why JAXB chooses to generate annotations for those I don't know.

You could include theVersion by adding getTheVersion() accessor (or anything that's valid as getter, signature-wise, and using one of annotations to rename it), but there is no way to include static fields with Jackson.

@redblue36
Copy link
Author

redblue36 commented Aug 17, 2016

@cowtowncoder Interested in some insight on the design/technical consideration for static exclusion. I'm a Jackson newbie..but willing to apply some time towards an enhancement proposal if in realm of possibility.

I think JAXB sees the "fixed" value as a constant and uses public final static as it's implementation to force/ensure that (with no getter).

As a simple aside, it is interesting Moxy can handle this scenario...but since Moxy has other issues for me, more interested in a Jackson solution. Would like to understand if a Jackson enhancement is technically possible and I should dig around in the code. Or go down the path of attempting to customize the JAXB class generation. Thoughts?

@cowtowncoder
Copy link
Member

@redblue36 This limitation has been there from the beginning, and my understanding is that most if not all serialization packages would exclude static fields. Since they are dropped early on in the process, there might not be easy fix for this at this point.

Interesting to learn about this as I was not aware that JAXB would allow annotation of static members this way. I can see how it could be useful, just something that I haven't seen used before.
I am still bit surprising to see fixed XML attributes bound to Java static constant. I really would have expected to see an accessor (getter) being generated, since all Java tooling would expect such to exist. But be that as it may.

If you wanted to see if it was possible to change property detection to handle removal of static member at a later point I would not be opposed to allowing such usage. But it may not be trivial to do, especially given size of Jackson code base. If you do want to take a look, relevant code would be in jackson-databind: all JAXB annotations are in a way translated (by this module) into equivalent of jackson annotations, so this module does not implement much functionality beyond mapping of types.
Specific classes would be in package com.fasterxml.jackson.databind.introspect: POJOPropertiesCollector and POJOPropertyBuilder.

@cowtowncoder
Copy link
Member

Project moved to:

https://github.com/FasterXML/jackson-modules-base/issues

so if follow-up desired (at this point I'd consider it "work as intended although different from JAXB").

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

No branches or pull requests

2 participants