FasterXML / FasterXML/jackson-modules-base

Registering JaxbAnnotationModule causes custom PropertyNamingStrategy to be ignored

Open
#137 4 comments 0 reactions 0 assignees View on GitHub
jaxb-annotations
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.