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.
source to share
No one has answered this question yet
Check out similar questions: