Annotation Kullanarak XStream

Önceki XStream ile ilgili yazıdaXStream kullanarak, XML dosyalarının manuel olarak nasıl oluşturulabileceğine bakmıştık. Örnek olarakta bir projeye ait veritabanı ayarlarının dosyadan alınmasını yapmıştık. Fakat projelerinizde düzenli olarak XStream kullanıyorsanız, belli bir yerden sonra manuel olarak XML dosyalarını oluşturma işinden sıkılıyorsunuz. Bunu Annotation kullaranak nasıl yapabileceğinizi düşünmeye başlıyorsunuz.

XStream Annotation


Geçtiğimiz günlerde üzerinde çalıştığımız projede, XML dosyalarımızı okuma ve yaratma işlemini Java’nın kendi sınıflarından, XStream üzerine taşımaya karar verdik. Fakat beni sıkan şey manuel olarak XStream sınıflarını oluşturmak oldu. Bundan dolayı bu işin annotation yapsının kullanılarak nasıl yapılacağını düşünmeye başladım. Sonradan bu durumun sadece beni sıkmış olmayacağının farkına vardım ve interneti araştırmaya koyuldum. Öğrendim ki zaten XStream içerisinde kolaylıkla kullanılabilen annotation yapıları mevcutmuş. İşte bu yazıda bu annotation yapılarının nasıl kullanılabileceğimize bakacağız.

Giris

Öncelikle üzerinde çalışacağımız projeden bahsedelim. Basit bir konsol uygulması üzerinden anlatacağım. İsterseniz Android, Wicket ya da arzu ettiğiniz başka framework’ler ve ortamlarda da rahatlıkla kullanabilirsiniz. Şahsen geçen gün Android üzerinden bağlandığım Rest web servisinden gelen XML cevabını nesneye dönüştürmek için XStream’i kullandım.

Her zaman ki gibi projemizi Maven kullanarak yöneteceğim. Bu örnekte kullanacağımız maven archetype’ı klasik, maven-archetype-quickstart olacak. Bağımlılık olarak sadece aşağıdaki XStream bağımlılığını girmeniz yeterli olacaktır.

<dependencies>
<!-- XSTREAM DEPENDENCY -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.2</version>
</dependency>
...
</dependencies>

Modeller ve Annotation

Basit olması açısından, bir kullanıcı sınıfı yaratalım. Basit olarak sadece id ve kullanıcı adı bilgisi taşısın. Daha sonra ise annotation kullanarak bu sınıfı yönetelim. Sınıfın XML dosyasına nasıl yazılacağını, ve XML Dosyasından nasıl okunacağını bir sonraki adımda anlatacağım.

package com.bahadirakin.xstream.model;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("user")
public class User {

@XStreamAlias("id")
private int id;
@XStreamAlias("userName")
private String userName;

public User() {
id = -1;
userName = "";
}

public User(int id, String userName) {
super();
this.id = id;
this.userName = userName;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

@Override
public String toString() {
return "UserName: " + userName + " with id: " + id;
}
}

XStream tarafından sağlanan ve en çok kullanacağınızı düşündüğüm annotation, XStreamAlias. Temel olarak nesnenin içeriğini annotation içerisinde verdiğiniz tag adının içerisine yerleştiriyor. Yani ileride user nesnesini XML olarak serileştirdiğimizde aşağıdaki XML çıktısını elde edeceğiz.

user.xml

<user>
<id>1</id>
<userName>bhdrkn</userName>
</user>

Temel Annotation Sınıfları

[fancy_list style=”triangle_arrow” variation=”blue”]

  • XStreamAlias: Bu annotation sınıfı, XStream sınıflarının belirtilmesinde kullanılıyor. Eğer sınıfınız başında XStreamAlias kullanmazsanız, XML oluştururken sorun yaşayabilirsiniz. Fakat alanlarınızda kullanmazsanız, alan adınız doğrudan tag olarak atanır. Bizim örneğimiz için eğer userName alanına XStreamAlias atamasaydık da sonuç değişmeyecekti.
  • XStreamAsAttribute: Bu annotation, XStream sınıfınız içerisindeki bir alanın XML özelliği olarak tanımlanmasına yarıyor. Örneğin, eğer id alanımız XStreamAsAttribute olarak tanımlansaydı XML yapımız <user id=”1″> <userName>bhdrkn</userName></user> şeklinde oluşturulacaktı.
  • XStreamOmitField: Bu annotation sınıfı, serileştirmek istemediğiniz alanları belirtmenizde kullanılıyor. Örneğin sınıfınız içerisinde sabit alanlar varsa bunların serileştirilmesini bu annotation sınıfını kullanarak engelleyebilirsiniz.
  • XStreamImplicit: Bu annotation sınıfı, liste veya dizilerinizi serileştirmek için kullanılıyor.

[/fancy_list]

XStream Factory Sınıfı

Bu işlemi önceki XStream yapısında da yapmıştık. Fakat şimdi daha generic olarak tekrarlayalım. Belirtmekte fayda var tek değişen kısım, XStream nesnenizin ayarlanması olacaktır. Generikliği sağlamak adına, IXmlFactory ve AbstractXmlFactory sınıfları oluşturulmuştur.

[toggle title=”IXmlFactory.java” variation=”blue”]

public interface IXmlFactory extends Serializable{

    void toXmlFile(T t, String filePath);

    T fromXmlFile(String filePath);

    T fromXmlString(String xmlString);

    String toXmlString(T t);
}

[/toggle]
[toggle title=”AbstractXmlFactory.java” variation=”blue”]

public abstract class AbstractXmlFactory implements IXmlFactory {

    private static final long serialVersionUID = 1L;
    protected XStream xStream = null;

    public AbstractXmlFactory() {
        super();
        xStream = new XStream(new DomDriver());
        xStream.processAnnotations(((Class) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0]));
        xStream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);
    }

    public void toXmlFile(final T t, final String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                file.createNewFile();
            }
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
                    file));
            xStream.toXML(t, bufferedWriter);
        } catch (Exception e) {
            System.err.println("Exception in toXmlFile M:" + e.getMessage()
                    + " C: " + e.getCause() + " ST: " + e.getStackTrace());
        }
    }

    public T fromXmlFile(final String filePath) {
        T t = null;
        try {
            File file = new File(filePath);
            BufferedReader bufferedReader = new BufferedReader(new FileReader(
                    file));
            t = ((T) this.xStream.fromXML(bufferedReader));
        } catch (Exception e) {
            System.err.println("Exception in fromXmlFile M:" + e.getMessage()
                    + " C: " + e.getCause() + " ST: " + e.getStackTrace());
        }

        return t;
    }

    public String toXmlString(final T t) {
        return this.xStream.toXML(t);
    }

    public T fromXmlString(String xmlString) {
        T t = null;
        t = ((T) this.xStream.fromXML(xmlString));
        return t;
    }
}

[/toggle]

Generic sınıflarımızı oluşturduktan sonra tek yapmamız gereken, her model sınıfımız için ilgili factory sınıfını oluşturmak. Bunu kodunuzun içerisinde kullanım sırasında yapabileceğiniz gibi, sınıfı doğrudan da oluşturabilirsiniz. Ben doğrudan oluşturmayı seçip, UserXmlFactory sınıfını yazdım.

UserXmlFactory.java

public class UserXmlFactory extends AbstractXmlFactory<User> {

private static final long serialVersionUID = 1L;

public static final String USER_XML_FILE = "user.xml";

public UserXmlFactory() {
super();
}
}

Test

Son olarak yazılan kodun test edilmesi kalıyor. Bunun için projenin oluşturulmasıyla yaratılmış App sınıfını kullanabiliriz. Test için App sınıfını aşağıdaki gibi değiştiriyoruz.

App.java

public class App {

public static void main(String[] args) {
App app = new App();
System.out.println("XSTREAM TEST APP STARTED");
app.createUserXml();
System.out.println("*** USER XML FILE CREATED");
User user = app.readFromUserXml();
System.out.println("*** USER XML FILE READ: " + user.toString());
System.out.println("End Of Line");
}

public void createUserXml() {
User user = new User(1, "bhdrkn");
UserXmlFactory factory = new UserXmlFactory();
factory.toXmlFile(user, UserXmlFactory.USER_XML_FILE);
}

public User readFromUserXml() {
return new UserXmlFactory().fromXmlFile(UserXmlFactory.USER_XML_FILE);
}

}

Yukarıdaki kodu derleyip çalıştırdığınızda aşağıdaki konsol çıktılarını ve aşağıdaki user.xml dosya çıktısını elde edeceksiniz.

[toggle title=”Konsol” variation=”blue”]

[/toggle]
[toggle title=”user.xml” variation=”blue”]

<user>
<id>1</id>
<userName>bhdrkn</userName>
</user>

[/toggle]

Kaynaklar

GitHub Adresi: https://github.com/bhdrkn/Java-Examples/tree/master/XStreamAnnotation

End Of Line