2

タグに含まれる要素の順序をキャプチャする作業をしていました。すべてのコードは次のとおりです。

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 は何らかの形で @Attribute in League に干渉しますか?

4

3 に答える 3

5

この質問は (SimpleXML ライブラリーのように) 非常に古いものですが、2 セントを差し上げます。

@Convertアノテーションは@Elementでのみ機能しますが、 @Attributeには影響しません。それがバグなのか機能なのかはわかりませんが、Transform with Matcherと呼ばれるカスタムのシリアル化されたオブジェクトを処理する別の方法があり、 AttributesElementsの両方で機能します。Converterを使用する代わりに、シリアル化と逆シリアル化を処理するTransformクラスを定義します。

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クラスを作成し、 RegistryMatcherインスタンスとともにAnnotationStrategyに渡すことができます。以下のファクトリ メソッドでは、インデント フォーマッタも使用します。

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を作成します。

于 2016-11-10T20:12:03.323 に答える
1

@Convert注釈はフィールドでのみ機能します@Element。私@Attributeもフィールドの変換に苦労していますが、今のところ成功していません...

于 2014-03-12T10:50:04.697 に答える