본문 바로가기

XML & WebServices

[XStream] XStream 사용예

crescent에서 색인 설정 파일을 xml로 정의하고 있습니다.

collections.xml인데요... 본래 이걸 그냥 dom4j를 사용해서 읽어서 Map과 기타 필요한 오브젝트를 생성하는

형태로 만들어서 사용하고 있었습니다.


그러다보니.. webpage에서 이 collections.xml설정을 변경하는 기능을 추가하려보니..

저런 형태로는 다루기가 어려울 것 같아서 XML과 POJO의 변환에 관련된 라이브러리를 찾아보다가

XStream을 알게되어 처음 사용해보았습니다.


꽤 오래전부터 많이 사용되던 것 같은데..

왜 몰랐을까요 -_-;


http://xstream.codehaus.org


예제도 잘 나와있습니다.


이걸 사용해서 collections.xml을 변환해본 예제입니다. xml 자체가 그리 복잡하지 않아서..

특별히 어려운 내용은 없습니다.


XStream 사용하시는 분들께서 예제로 보시면 좋을 것 같아서 올려봅니다.

<?xml version="1.0" encoding="UTF-8"?>
<collections>
<collection name="sample">
<analyzer>com.tistory.devyongsik.analyzer.KoreanAnalyzer</analyzer>
<indexingDirectory>/Users/need4spd/Programming/Java/crescent_index/sample</indexingDirectory>
<!-- indexingDirectory>/data1/lucene_index/sample</indexingDirectory -->
<!-- indexingDirectory>/Users/need4spd/Programming/Java/workspace/crescent/test/crescent_index/sample</indexingDirectory -->
<fields>
<!-- type : string, long, int -->
<field name="board_id" store="true" index="true" type="long" analyze="false" termposition="false" termoffset="false" />
<field name="title" store="true" index="true" type="string" analyze="true" boost="2.0" />
<field name="dscr" store="true" index="true" type="string" analyze="true" must="true" termvector="true" />
<field name="creuser" store="true" index="false" type="string" analyze="false" />
</fields>
<defaultSearchFields>
<defaultSearchField name="title" />
<defaultSearchField name="dscr" />
</defaultSearchFields>
<sortFields>
<sortField source="title" dest="title_sort" />
<sortField source="board_id" dest="board_id_sort" />
</sortFields>
</collection>
<collection name="sample_wiki">
<analyzer>com.tistory.devyongsik.analyzer.KoreanAnalyzer</analyzer>
<indexingDirectory>/Users/need4spd/Programming/Java/crescent_index/sample_wiki</indexingDirectory>
<!-- indexingDirectory>/data1/lucene_index/glider_wiki</indexingDirectory -->
<!-- indexingDirectory>/Users/need4spd/Programming/Java/workspace/crescent/test/crescent_index/glider_wiki</indexingDirectory -->
<fields>
<!-- type : string, long, int -->
<field name="wiki_idx" store="true" index="true" type="long" analyze="false" />
<field name="space_idx" store="true" index="true" type="long" analyze="false" />
<field name="wiki_text" store="true" index="true" type="string" analyze="true" must="true" termvector="true" />
<field name="wiki_title" store="true" index="true" type="string" analyze="true" must="true" boost="2.0" />
<field name="ins_user" store="true" index="true" type="string" analyze="false" />
<field name="ins_date" store="true" index="true" type="long" analyze="false" />
</fields>
<defaultSearchFields>
<defaultSearchField name="wiki_title" />
<defaultSearchField name="wiki_text" />
</defaultSearchFields>
<sortFields>
<sortField source="ins_date" dest="ins_date_sort" />
<sortField source="wiki_idx" dest="wiki_idx_sort" />
</sortFields>
</collection>
</collections>
view raw collections.xml hosted with ❤ by GitHub


현재 사용되고 있는 xml인데요.. XStream을 사용하기 위해서 각 엘리먼트들을 전부 클래스로 만들었습니다.

여기서는 최상위 Root를 나타내는 CrescentCollections 와 그 하위인 CrescentCollection

그리고 CrescentCollection 하위로 들어가는 CrescentCollectionField, CrescentDefaultSearchField, CrescentSortField가 만들어졌습니다.


indexingDirectory와 analyzer 부분은 CrescentCollection의 field로 들어갑니다.



CrescentCollections.java
package com.tistory.devyongsik.domain;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
@XStreamAlias("collections")
public class CrescentCollections {
@XStreamImplicit(itemFieldName="collection")
private List crescentCollections = null;
@XStreamOmitField
private Map crescentCollectionsMap = null;
public Map getCrescentCollectionsMap() {
lazyLoadMap();
return crescentCollectionsMap;
}
public void setCrescentCollectionsMap(
Map crescentCollectionsMap) {
this.crescentCollectionsMap = crescentCollectionsMap;
}
public List getCrescentCollections() {
return crescentCollections;
}
public void setCrescentCollections(List crescentCollections) {
this.crescentCollections = crescentCollections;
}
@Override
public String toString() {
return "CrescentCollections [crescentCollections="
+ crescentCollections + "]";
}
}

XStream의 annotation을 사용하였고요..

@XStreamAlias로 지정된 name 값이 엘리먼트명이 되고..

@XStreamOmitField로 지정된 field는 XML의 변환에서 제외됩니다.


@XStreamImplicit(itemFieldName="collection")
	private List crescentCollections = null;

이 부분은.. <collections></collections>가 하위에 <collection></collection>을 2개 가지고 있는데 그것을 나타내기 위한 설정입니다. 추후 실제 XML로 변환하는 코드에서 추가로 말씀을 드리겠습니다.


getter, setter 메서드는 코드에서는 생략했습니다.

CrescentCollection.java
package com.tistory.devyongsik.domain;
import java.util.List;
import java.util.Map;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
@XStreamAlias("collection")
public class CrescentCollection {
private String analyzer;
@XStreamAsAttribute
private String name;
private String indexingDirectory;
@XStreamOmitField
private Map crescentFieldByName;
private List fields;
private List defaultSearchFields;
private List sortFields;
public String getAnalyzer() {
return analyzer;
}
}

<collection></collection>이 가지고 있는 항목들을 표한하기 위한 설정들이 들어가있습니다.

@XStreamAsAttribute 이 설정을 가지고 있는 field는 xml에서 속성으로 표현됩니다.

<collection name="sample"> 과 같은 형태로요...




CrescentCollectionField.java
package com.tistory.devyongsik.domain;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.SortField;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
@XStreamAlias("field")
public class CrescentCollectionField implements Cloneable {
@XStreamAsAttribute
private String name;
@XStreamAsAttribute
private boolean store;
@XStreamAsAttribute
private boolean index;
@XStreamAsAttribute
private String type;
@XStreamAsAttribute
private boolean analyze;
@XStreamAsAttribute
private boolean termposition;
@XStreamAsAttribute
private boolean termoffset;
@XStreamAsAttribute
private float boost;
@XStreamAsAttribute
private boolean must;
@XStreamAsAttribute
private boolean termvector;
}

<field></field>는 전부 속성으로 되어있기 때문에 특별한 설정은 없고.. 다만 위 xml예에서는 각 속성이 <field></field>로 조금씩 다른데.. 위와 같이 사용하기 위해서는 필드가 전부 동일해야 하겠죠... 




CrescentDefaultSearchField.java
package com.tistory.devyongsik.domain;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
@XStreamAlias("defaultSearchField")
public class CrescentDefaultSearchField {
@XStreamAsAttribute
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "CrescentDefaultSearchField [name=" + name + "]";
}
}


<defaultSearchField/>나 <sortField/>는 거의 비슷하기 때문에 하나만...

이제 이 XML을 POJO로 변환하는 코드입니다.




Test
XStream stream = new XStream();
stream.processAnnotations(CrescentCollections.class);
//stream.alias( "collections", CrescentCollections.class );
//stream.addImplicitCollection( CrescentCollections.class, "crescentCollections" );
ResourceLoader resourceLoader = new ResourceLoader();
InputStream inputStream = resourceLoader.openResource("경로");
CrescentCollections crescentCollections = (CrescentCollections)stream.fromXML(inputStream);
view raw Test.java hosted with ❤ by GitHub

위와같이 해주시면 되는데...

processAnnotation은 최상위 클래스만 걸어주시면 됩니다.