根据Dave 的描述,我们有类似的要求。一个有效的解决方案是基于 Java 反射。
这个想法是在运行时为属性设置 propOrder。在我们的例子中,APP_DATA 元素包含三个属性:app、key和value。生成的 AppData 类在 propOrder 中包含“内容”,并且没有其他属性:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AppData", propOrder = {
"content"
})
public class AppData {
@XmlValue
protected String content;
@XmlAttribute(name = "Value", required = true)
protected String value;
@XmlAttribute(name = "Name", required = true)
protected String name;
@XmlAttribute(name = "App", required = true)
protected String app;
...
}
所以使用Java反射在运行时设置顺序如下:
final String[] propOrder = { "app", "name", "value" };
ReflectionUtil.changeAnnotationValue(
AppData.class.getAnnotation(XmlType.class),
"propOrder", propOrder);
final JAXBContext jaxbContext = JAXBContext
.newInstance(ADI.class);
final Marshaller adimarshaller = jaxbContext.createMarshaller();
adimarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
true);
adimarshaller.marshal(new JAXBElement<ADI>(new QName("ADI"),
ADI.class, adi),
new StreamResult(fileOutputStream));
changeAnnotationValue() 是从这篇文章中借来的:
Modify a class definition's annotation string parameter at runtime
这是为您提供方便的方法(归功于@assylias 和@Balder):
/**
* Changes the annotation value for the given key of the given annotation to newValue and returns
* the previous value.
*/
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue) {
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key, newValue);
return oldValue;
}