【问题标题】:Android - Simple XML Framework. @Convert interferes with @Attribute - How to solve this?Android - 简单的 XML 框架。 @Convert 干扰@Attribute - 如何解决这个问题?
【发布时间】:2013-07-15 06:48:02
【问题描述】:

我正在努力捕获标签中包含的元素的顺序。以下是全部代码:

League.java:

@Root
@Convert(value = LeagueConverter.class)
public class League 
{
    @Attribute
    private String name;

    @Element(name="headlines", required = false)
    private Headlines headlines;

    @Element(name="scores", required = false)
    private Scores scores;

    @Element(name="standings", required = false)
    private Standing standings;

    @Element(name="statistics", required = false)
    private LeagueStatistics statistics;

    public List<String> order = new ArrayList<String>();

        // get methods for all variables
}

LeagueConverter.java:

public class LeagueConverter implements Converter<League>
{
       @Override
       public League read(InputNode node) throws Exception
       {
               League league = new League();
               InputNode next = node.getNext();
               while( next != null )
               {
                String tag = next.getName();
                if(tag.equalsIgnoreCase("headlines"))
                {
                  league.order.add("headlines");
                }
                else if(tag.equalsIgnoreCase("scores"))
                    {
                          league.order.add("scores");
                    }
                else if(tag.equalsIgnoreCase("statistics"))
                {
                  league.order.add("statistics");
                }
                else if(tag.equalsIgnoreCase("standings"))
                {
                  league.order.add("standings");
                }
                    next = node.getNext();
                }
                return league;
       }
   @Override
   public void write(OutputNode arg0, League arg1) throws Exception 
   {
    throw new UnsupportedOperationException("Not supported yet.");
   }
}

XML 示例:

 <android>
    <leagues>
       <league name ="A">
          <Headlines></Headlines>
          <Scores></Scores>
          ...
       </league>
       <league name ="B">...</league>
    </leagues>
 </android>

我如何称呼它并期望它的行为:(片段)

 Android android = null;
 Serializer serial = new Persister(new AnnotationStrategy());

 android = serial.read(Android.class, source);
 Log.i("Number of leagues found ",tsnAndroid.getLeagueCount() + ""); // prints fine
 League nhl = tsnAndroid.getLeagues().get(0); // works fine

 // DOES NOT WORK throws NullPointerEx
 League nhl2 = tsnAndroid.getLeagueByName("A");
 // DOES NOT WORK throws NullPointerEx

 for(String s : nhl.getOrder())
 {
    Log.i("ORDER>>>>>", s);
 }

问题:

android.getLeagueByName()(与@Attribute 名称一起使用)在我设置转换器时突然停止工作,所以它就像League.java 中的以下内容一样,永远不会设置。

@Attribute
private String name; // not being set

但是,当我在 League.java 中注释掉转换器声明时 - 每个联赛都有一个名为 name 的属性,android.getLeagueByName() 开始正常工作...

@Convert for League 是否会以某种方式干扰 League 中的 @Attribute?

【问题讨论】:

  • getLeagueByName() 在做什么?您是否检查过您的联赛列表是否包含任何 not-null 值?可能列表具有正确的元素数量,但它们都是null
  • 我刚刚查看了回归的联赛。似乎当我注释掉@convert - 联赛本身是空的,因为 android 元素不解析。但是我不确定为什么。
  • 你可以调试每个反序列化(每个对象),可能只有一个失败并导致null

标签: android xml-parsing converter simple-framework


【解决方案1】:

@ElementListUnion 将捕获元素的顺序

【讨论】:

  • 这不是只有在联合中的所有元素都是元素列表的情况下才有效吗?
【解决方案2】:

@Convert 注释仅适用于 @Element 字段。我也在努力转换 @Attribute 字段,但现在没有成功......

【讨论】:

【解决方案3】:

即使这个问题已经过时了(SimpleXML 库也是如此),我还是愿意付出两分钱。

@Convert 注释仅适用于 @Element,但对 @Attribute 没有任何影响。我不确定这是错误还是功能,但还有另一种处理自定义序列化对象的方法 - 使用 Matcher 调用 Transform,它可以与 一起使用>属性元素。您可以定义一个处理序列化和反序列化的 Transform 类,而不是使用 Converter

import java.util.UUID;
import org.simpleframework.xml.transform.Transform;

public class UUIDTransform implements Transform<UUID> {
    @Override
    public UUID read(String value) throws Exception {
        return value != null ? UUID.fromString(value) : null;
    }
    @Override
    public String write(UUID value) throws Exception {
        return value != null ? value.toString() : null;
    }
}

如您所见,它比实现 Convert 接口更直接!

为所有需要自定义反序列化/序列化的对象创建一个类似的类。

现在实例化一个 RegistryMatcher 对象并在那里注册您的自定义类及其对应的 Transform 类。这是一个内部使用缓存的线程安全对象,因此将其保留为单例可能是个好主意。

private static final RegistryMatcher REGISTRY_MATCHER = new RegistryMatcher();
static {
    try {
        REGISTRY_MATCHER.bind(UUID.class, UUIDTransform.class);
        // register all your Transform classes here...
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

最后,您可以在每次转换之前创建一个 Persister 类,并将 AnnotationStrategy 与您的 RegistryMatcher 实例一起传递给它。在下面的这个工厂方法中,我们还将使用缩进格式化程序:

private static Persister createPersister(int indent) {
    return new Persister(new AnnotationStrategy(), REGISTRY_MATCHER, new Format(indent));
}

现在您可以制作序列化/反序列化方法了:

public static String objectToXml(Object object, int indent) throws MyObjectConversionException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    Persister p = createPersister(indent);
    try {
        p.write(object, out, "UTF-8");
        return out.toString("UTF-8");
    } catch (Exception e) {
        throw new MyObjectConversionException("Cannot serialize object " + object + " to XML: " + e.getMessage(), e);
    }
}

public static <T> T xmlToObject(String xml, final Class<T> clazz) throws MyObjectConversionException {
    Persister p = createPersister(0);
    try {
        return (T) p.read(clazz, xml);
    } catch (Exception e) {
        throw new MyObjectConversionException(
                "Cannot deserialize XML to object of type " + clazz + ": " + e.getMessage(), e);
    }
}

这种方法的唯一问题是当您想为同一个对象设置不同的格式时 - 例如一旦您希望 java.util.Date 仅具有日期组件,而稍后您还希望拥有时间组件。然后只需扩展 Date 类,将其命名为 DateWithTime,并为其创建不同的 Transform

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 2023-04-03
    相关资源
    最近更新 更多