FasterXML / FasterXML/jackson-modules-base
Registering JaxbAnnotationModule causes custom PropertyNamingStrategy to be ignored
- Dominant language
- Java
- Stars
- 180
- Forks
- 80
- Avg merge
- 3h 26m
- Merged PRs (30d)
- 1
Description
I am trying to use the JaxbAnnotationModule when serialising a jaxb object to string. I am trying to achieve two things:
1. enums should be serialised with the jaxb enum value, rather than the java enum name
2. xml attributes names should be prefixed with the '@' symbol
I had hoped to use JaxbAnnotationModule to achieve 1. and a custom PropertyNamingStrategy to achieve 2. They work separately, but when I try to use both together, the custom PropertyNamingStrategy seems to never be invoked.
I don't know if my approach is wrong, or if this is a bug. Any help would be appreciated. Below is a pom.xml and junit 5 test that should reproduce the issue.
```xml
4.0.0
com.example
jaxb-jackson
0.0.1-SNAPSHOT
maven-surefire-plugin
2.22.2
com.fasterxml.jackson.module
jackson-module-jaxb-annotations
2.12.3
org.junit.jupiter
junit-jupiter-api
5.7.2
test
org.junit.jupiter
junit-jupiter-engine
5.7.2
test
```
```java
package com.example.jaxbjackson;
import static org.junit.jupiter.api.Assertions.assertEquals;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
public class JaxbToJsonConverterTest {
@Test
public void usesCustomPropertyNamingStrategy() throws Exception {
AnXmlElement xmlelement = new AnXmlElement();
xmlelement.setAnXmlAttribute(AnXmlAttributesEnumValue.VALUE_ONE);
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new AtSymbolPropertyNamingStrategy());
String json = mapper.writeValueAsString(xmlelement);
String[] split = json.split(":");
assertEquals("{\"@AnXmlAttribute\"", split[0]);
}
@Test
public void usesJaxBAnnotationToDeriveEnumValue() throws Exception {
AnXmlElement xmlelement = new AnXmlElement();
xmlelement.setAnXmlAttribute(AnXmlAttributesEnumValue.VALUE_ONE);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());
String json = mapper.writeValueAsString(xmlelement);
String[] split = json.split(":");
assertEquals("\"Value One\"}", split[1]);
}
@Test
public void usesJaxBAnnotationAndCustomPropertyNamingStrategyTogether() throws Exception {
AnXmlElement xmlelement = new AnXmlElement();
xmlelement.setAnXmlAttribute(AnXmlAttributesEnumValue.VALUE_ONE);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());
mapper.setPropertyNamingStrategy(new AtSymbolPropertyNamingStrategy());
String json = mapper.writeValueAsString(xmlelement);
String[] split = json.split(":");
// below assertion fails because AtSymbolPropertyNamingStrategy is ignored
assertEquals("{\"@AnXmlAttribute\"", split[0]);
assertEquals("\"Value One\"}", split[1]);
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "AnXmlElement")
static class AnXmlElement {
@XmlAttribute(name = "AnXmlAttribute")
protected AnXmlAttributesEnumValue anXmlAttribute;
public AnXmlAttributesEnumValue getAnXmlAttribute() {
return anXmlAttribute;
}
public void setAnXmlAttribute(AnXmlAttributesEnumValue value) {
this.anXmlAttribute = value;
}
}
@XmlType(name = "anXmlAttributesEnumValues")
@XmlEnum
static enum AnXmlAttributesEnumValue {
@XmlEnumValue("Value One")
VALUE_ONE("Value One");
private final String value;
AnXmlAttributesEnumValue(String v) {
value = v;
}
public String value() {
return value;
}
public static AnXmlAttributesEnumValue fromValue(String v) {
for (AnXmlAttributesEnumValue c: AnXmlAttributesEnumValue.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
@SuppressWarnings("serial")
static class AtSymbolPropertyNamingStrategy extends PropertyNamingStrategy {
private String fieldName(AnnotatedMember member, String defaultName) {
XmlAttribute xmlAttributeAnnotation = member.getAllAnnotations().get(XmlAttribute.class);
if (xmlAttributeAnnotation != null) {
return "@" + xmlAttributeAnnotation.name();
}
return defaultName;
}
@Override
public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) {
return fieldName(method, defaultName);
}
@Override
public String nameForField(MapperConfig config, AnnotatedField field, String defaultName) {
return fieldName(field, defaultName);
}
@Override
public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) {
return fieldName(method, defaultName);
}
}
}
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.