jackson-modules-base icon indicating copy to clipboard operation
jackson-modules-base copied to clipboard

ClassCastException when using XmlAdapter with XmlEnum

Open wbiller opened this issue 1 year ago • 4 comments

I wanted to serialize a fairly complex object structure and came across this ClassCastException. It looks like the XML Adapter is called too early when the type is an enum.

Below snippet demonstrates the error as a JUnit test


import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import org.junit.jupiter.api.Test;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;

import static org.assertj.core.api.Assertions.assertThat;

public class XmlEnumAdapterTest {

  private static final XmlMapper MAPPER =
    XmlMapper.builder()
             .defaultUseWrapper(true)
             .addModule(new JaxbAnnotationModule())
             .build();

  @Test
  void serialize() throws Exception {

    final Document document = new Document(Code.RED);

    String xml = MAPPER.writeValueAsString(document);

    assertThat(xml).isEqualTo("<document><code>RED</code></document>");
  }

  @XmlRootElement(
    name = "document"
  )
  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlType(
    propOrder = {"_code"}
  )
  public static class Document {

    @XmlElement(name = "code")
    private final Code _code;

    public Document(Code code) { _code = code; }

    public Code getCode() {
      return _code;
    }
  }

  @XmlEnum
  @XmlType(
    name = "CodeType"
  )
  @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
  public enum Code {

    @XmlEnumValue("RED")
    RED;
  }
}

The test was executed with jackson-module-jaxb-annotations-2.17.2.jar

wbiller avatar Nov 19 '24 20:11 wbiller

First of all, thank you for reporting the issue.

Figuring out where to add tests is tricky: JAXB annotations module cannot depend on XML module (so can't be added here).

But looks like jackson-dataformat-xml does actually have test dependency on Jakarta XML bind annotations -- newer version of JAXB annotations. So might be able to add there.

However, the "correct" place would be here:

https://github.com/FasterXML/jackson-integration-tests/

where it is legal to have dependencies to any and all Jackson modules.

cowtowncoder avatar Nov 19 '24 23:11 cowtowncoder

Is there anything I could/should do?

wbiller avatar Nov 20 '24 10:11 wbiller

@wbiller No, I think this is all the information. I am pretty overloaded currently so it may take a while until I get to look into this, unfortunately.

One minor thing could be if you could try to find minimal reproduction (I suspect most JAXB annotations used are not required here). And perhaps including first couple of stack frames for exception.

But reproduction is the most important thing and you got it :)

cowtowncoder avatar Nov 21 '24 05:11 cowtowncoder

Just realized that XML is probably not the problem here: can create JSON reproduction as well.

But looking at what is happening, I am not sure how code is supposed to work. CollapsedStringAdapter is "converting" between String and String, basically just transforming content a bit. But when serializing Enums, shouldn't type given (see https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html) be Enum type, not String? Only on deserialization could we get String (to convert/adapt to Enum type in question).

Does this work with JAXB? (I assume so).

If this is expected to work there's bit of impedance between how Jackson Converters and JAXB XmlAdapters work and it may be tricky to support these annotations with Jackson.

cowtowncoder avatar Nov 24 '24 05:11 cowtowncoder