问题
I need to generate XML from java objects on Android. XML nodes must be in definite sequence. Here is what I got(These fields as according to alphabetical order):
<soap:Envelope xmlns:cwmp="urn:dslforum-org:cwmp-1-0"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<cwmp:Inform>
<CurrentTime>2013-06-07 07:11:20.561 UTC</CurrentTime>
<DeviceId>
<OUI>002615</OUI>
<Manufacturer>Conexant</Manufacturer>
<ProductClass>ADSL2+ IAD</ProductClass>
<SerialNumber>00261559a496</SerialNumber>
</DeviceId>
<Event soapenc:arrayType="cwmp:EventStruct[1]">
<EventStruct>
<CommandKey></CommandKey>
<EventCode>0 BOOTSTRAP</EventCode>
</EventStruct>
</Event>
<ParameterList soapenc:arrayType="cwmp:ParameterValueStruct[1]">
<ParameterValueStruct>
<name>InternetGatewayDevice.DeviceInfo.SpecVersion</name>
<value>1.0</value>
</ParameterValueStruct>
</ParameterList>
<MaxEnvelopes>1</MaxEnvelopes>
<RetryCount>0</RetryCount>
</cwmp:Inform>
</soap:Body>
<soap:Header>
<ID soap:mustUnderstand="1">
<string>00001</string>
</ID>
</soap:Header>
</soap:Envelope>
Here is what I want it to be:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Header>
<ID soap:mustUnderstand="1">
<string>00001</string>
</ID>
</soap:Header>
<soap:Body>
<cwmp:Inform>
<DeviceId>
<Manufacturer>Conexant</Manufacturer>
<OUI>002615</OUI>
<ProductClass>ADSL2+ IAD</ProductClass>
<SerialNumber>00261559a496</SerialNumber>
</DeviceId>
<Event soapenc:arrayType="cwmp:EventStruct[1]">
<EventStruct>
<EventCode>0 BOOTSTRAP</EventCode>
<CommandKey></CommandKey>
</EventStruct>
</Event>
<MaxEnvelopes>0</MaxEnvelopes>
<CurrentTime>2013-06-07 07:16:54.128 UTC</CurrentTime>
<RetryCount>0</RetryCount>
<ParameterList soapenc:arrayType="cwmp:ParameterValueStruct[1]">
<ParameterValueStruct>
<name>InternetGatewayDevice.DeviceInfo.SpecVersion</name>
<value>1.0</value>
</ParameterValueStruct>
</ParameterList>
</cwmp:Inform>
</soap:Body>
</soap:Envelope>
I've investigated this problem more. And I found that Xstream handles fields in wrong order on Android. Xstream handles fields well in Java project.
@XStreamAlias("cwmp:Inform")
public class Inform {
@XStreamAlias("DeviceId")
private DeviceIdStruct deviceId;
@XStreamAlias("Event")
private EventList event;
@XStreamAlias("MaxEnvelopes")
private int maxEnvelopes;
@XStreamAlias("CurrentTime")
private Date currentTime;
@XStreamAlias("RetryCount")
private int retryCount;
@XStreamAlias("ParameterList")
private ParameterValueList parameterList;
}
回答1:
Here is my answer.
I researched the issue and concluded that Android returns fields in alphabetical order of field types.
You can inherit FieldKeySorter to set order.
First you need create annotation that will define fields order:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface XMLSequence {
String[] value();
}
And example using:
@XMLSequence({
"accountIds",
"addresses",
"birthDate",
"contact",
"name",
"status",
})
Then I've inherited FieldKeySorter :
public class SequenceFieldKeySorter implements FieldKeySorter {
@Override
public Map sort(final Class type, final Map keyedByFieldKey) {
Annotation sequence = type.getAnnotation(XMLSequence.class);
if (sequence != null) {
final String[] fieldsOrder = ((XMLSequence) sequence).value();
Map result = new OrderRetainingMap();
Set<Map.Entry<FieldKey, Field>> fields = keyedByFieldKey.entrySet();
for (String fieldName : fieldsOrder) {
if (fieldName != null) {
for (Map.Entry<FieldKey, Field> fieldEntry : fields) {
if
(fieldName.equals(fieldEntry.getKey().getFieldName())) {
result.put(fieldEntry.getKey(),
fieldEntry.getValue());
}
}
}
}
return result;
} else {
return keyedByFieldKey;
}
}
}
And finally go:
XStream x = new XStream(new PureJavaReflectionProvider(
new FieldDictionary(new SequenceFieldKeySorter())));
回答2:
- You can implement this interface FieldKeySorter for the classes you want to control the order.
- You can write an annotation by yourself, which does not only extend the target class but also implement FieldKeySorter at runtime by reflection. Finally replace the instance to control the order.
来源:https://stackoverflow.com/questions/16978651/how-to-annotation-order-field-when-using-xstream-on-android