JAXB Marshall XML Profile Filter
I have a need to order an object in XML using JAXB.
The Marshall / Unmarshall code works fine, but now we want to filter the resulting XML based on the annotation.
XmlProfile.java
@Retention (RUNTIME)
@Target({TYPE, METHOD, FIELD})
public @interface XmlProfile {
String[] value();
}
FooPojo.java
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class FooPojo {
@XmlElement
@XmlProfile("config")
public String bar;
@XmlElement
@XmlProfile("operational")
public String bartender;
@XmlElement
@XmlProfile({"config", "operational"})
public String spy;
}
I have read the JAXB documentation but I have not found any examples / threads of how to inject some code into the marshall process other than adapter or eventHandlers.
In particular, I read about event handlers, but I found support for pre-marshal / post-marshal events.
I was expecting to find a beforeFieldMarshal event, but this is not possible, so I decided to write a piece of code that scans the current object and sets null to properties that do not match the current profile:
private class ProfileListener extends Marshaller.Listener {
private String profile;
public ProfileListener(String profile) {
this.profile = profile;
}
@Override
public void beforeMarshal(Object source) {
if (source == null || profile == null || profile.length() == 0) return;
Field[] fields = source.getClass().getFields();
for (Field f : fields){
XmlProfile xmlProfile = f.getAnnotation(XmlProfile.class);
if (xmlProfile == null) continue;
String[] annValues = xmlProfile.value();
if (annValues == null
|| annValues.length == 0
|| findInArray(annValues)) {
continue;
}
// Remove from object
f.setAccessible(true);
try {
f.set(source, null);
} catch (Exception e) {
e.printStackTrace();
}
}
super.beforeMarshal(source); //To change body of generated methods, choose Tools | Templates.
}
private boolean findInArray(String[] annValues){
for (String annVal : annValues) {
if (profile.equalsIgnoreCase(annVal)){
return true;
}
}
return false;
}
}
The code works fine, also with nested object, this is the code I get:
Working Pojo
FooPojo fooPojo = new FooPojo();
fooPojo.bar = "Tijuana Cafe";
fooPojo.bartender = "Cynthia";
fooPojo.spy = "Antony Fisco";
fooPojo.phone = "555 555 555";
** XML result for configuration profile: **
<fooPojo>
<bar>Tijuana Cafe</bar>
<spy>Antony Fisco</spy>
<phone>555 555 555</phone>
</fooPojo>
** XML Result for Work Profile: **
<fooPojo>
<bartender>Cynthia</bartender>
<spy>Antony Fisco</spy>
<phone>555 555 555</phone>
</fooPojo>
but has a functional error that I don't know how to solve: the POJO is updated with code by setting null properties.
Is there a better way to do this? I may end up cloning the object and working on it, but I'm not sure if that's the right way.
No one has answered this question yet
Check out similar questions: