How to annotation order field when using XStream on Android?

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-22 18:23:25

问题


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:


  1. You can implement this interface FieldKeySorter for the classes you want to control the order.
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!