xml 직렬화 하기
XML 직렬화는 객체 퍼시스턴스와 데이터 전송을 포함한 무수히 많은 쓰임새가 있습니다. 그러나 일부 XML 직렬화 기술은 구현하기 어렵습니다. XStream은 자바 객체를 XML로 직렬화하거나 그 반대로 역직렬화할 수 있는 가볍고 사용하기 쉬운 오픈 소스 자바(Java™) 라이브러리입니다. XStream을 설정하고, 이를 이용해 객체를 직렬화하고 역직렬화하는 방법을 배웁니다. 또한 설정 속성들을 XML 설정 파일에서 읽어오는 방법도 알아봅니다.
XStream 을 사용하면, 대부분의 자바 객체를 아무런 매핑없이 직렬화할 수 있다. 객체 이름은 요소 이름이 되고, 클래스 내의 문자열들이 XML 요소의 내용을 구성한다. XStream으로 직렬화할 클래스는 Serializable 인퍼페이스를 구현할 필요도 없다. XStream은 직렬화 도구일 뿐, 데이터 바인딩 도구가 아니므로 XML이나 XML 스키마 정의(XML Schema Definition: XSD)로부터 클래스를 생성하지 않는다.
XStream은 다른 직렬화 도구와 구별되는 세 가지 특징이 있다.
- XStream은 클래스에서 직렬화/역직렬화될 필드들의 가시성을 고려하지 않는다.
- 클래스에서 직렬화/역직렬화될 필드들을 위한 getter나 setter 메서드가 필요없다.
- 직렬화/역직렬화될 클래스는 기본 생성자가 필요없다.
다음에 나오는 절차에 따라 XStream를 다운로드하고 설치하자(참고자료).
- 이클립스 웹 사이트에서 이클립스를 다운로드해 원하는 폴더에 설치하자. 해당 디렉터리를 이 기사에서는 eclipse_home으로 표기하겠다. 이 기사는 이클립스 3.3 버전을 기준으로 설명한다.
- XStream 웹 사이트에서 XStream의 최신 안정 버전을 다운로드해 원하는 폴더에 설치하자. 해당 디렉터리를 이 기사에서는 xstream_home으로 표기하겠다. 이 기사는 XStream 1.2.2 버전을 기준으로 설명한다.
- 3 썬 웹 사이트에서 자바 플랫폼 스탠다드 에디션(Java Platform, Standard Edition: J2SE) 소프트웨어 개발 킷(software development kit: SDK)을 다운로드해 원하는 폴더에 설치하자. 해당 디렉터리를 이 기사에서는 java_home으로 표기하겠다. 이 기사는 1.5.0_05 버전을 기준으로 설명한다.
File > New > Project를 선택하고, 다음 절차에 따라 자바 프로젝트를 생성하자.
- Java > Java Project > Next를 선택한다(그림 1).
그림 1. 새 자바 프로젝트 시작하기
- 프로젝트 이름을 입력하고 Next를 클릭한다(그림 2).
그림 2. 프로젝트 이름 채우기
- Finish를 클릭하여 작업을 마무리한다(그림 3).
그림 3. 설정 마무리하기
그림 4는 이렇게 해서 만들어진 자바 프로젝트를 보여준다.
그림 4. 새로 만들어진 자바 프로젝트
아래 절차에 따라 방금 만든 프로젝트에 XStream 라이브러리를 추가하자.
- 이클립스의 Project Explorer에서 해당 프로젝트를 선택한 다음, Project 메뉴에서 Properties를 선택한다(그림 5).
그림 5. XStream 라이브러리 추가하기
- Add External JARs를 클릭하고, xstream_home/lib 폴더에서 xstream-1.2.2.jar를 선택한다.
- OK를 클릭해 작업을 마무리한다(그림 6).
그림 6. XStream 지원 마무리하기
그림 7은 XStream 지원이 추가된 프로젝트를 보여준다.
그림 7. 추가된 라이브러리들
|
다음의 간단한 예제는 Writer와 Reader 클래스를 통해 XStream을 사용해 객체를 직렬화하고/역직렬화하는 방법을 보여준다. Writer 클래스는 Employee 타입의 객체를 XML로 직렬화해 파일로 저장하기 위해 XStream API를 사용한다(Listing 1).
Listing 1. Writer.java
package com.samples;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import com.thoughtworks.xstream.*;
public class Writer {
public static void main(String[] args) {
Employee e = new Employee();
//setter 메서드를 사용해 속성을 설정한다.
//주의: 이 작업은 생성자에서도 할 수 있지만
//XStream이 생성자 없이도 직렬화를 수행할 수 있음을 보여주기 위해
//일부러 이렇게 했다.
e.setName("Jack");
e.setDesignation("Manager");
e.setDepartment("Finance");
//객체를 직렬화한다.
XStream xs = new XStream();
//파일을 파일시스템에 기록한다.
try {
FileOutputStream fs = new FileOutputStream("c:/temp/employeedata.txt");
xs.toXML(e, fs);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
}
}
|
Reader 클래스는 이 파일을 읽어 XML을 역직렬화하고, 데이터로부터 자바 객체를 만들어 낸다(Listing 2).
Listing 2. Reader.java
package com.samples;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import com.thoughtworks.xstream.*;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class Reader {
public static void main(String[] args) {
XStream xs = new XStream(new DomDriver());
Employee e = new Employee();
try {
FileInputStream fis = new FileInputStream("c:/temp/employeedata.txt");
xs.fromXML(fis, e);
//방금 읽어들인 객체의 데이터를 출력한다
System.out.println(e.toString());
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
}
}
|
Listing 3은 Employee 객체의 구조를 보여준다.
Listing 3. Employee.java
package com.samples;
public class Employee {
private String name;
private String designation;
private String department;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return "Name : "+this.name+
"\nDesignation : "+this.designation+
"\nDepartment : "+this.department;
}
}
|
|
|
대 부분의 응용 프로그램은 다수의 설정 값(properties)에 의존한다. 이 설정 값은 연결할 데이터 소스의 이름일 수도 있고, 로그 파일의 위치일 수도 있다. 설정 파일은 응용 프로그램을 다시 컴파일하지 않고도 설정 값을 변경할 수 있도록 해주고, 유지보수도 쉬워지므로 이러한 데이터를 저장하기에 가장 적합한 곳이다. 이 예제 시나리오는 XStream을 사용하여 응용 프로그램에서 XML 설정 파일로부터 설정 값을 읽는 방법을 보여준다.
전형적인 XML 데이터 바인딩은 XML 파일로부터 자바 객체를 생성(generate)해야 하지만, XStream을 사용하면 객체 생성 단계가 필요없다. 자바 클래스를 만들고 클래스의 필드를 읽고 싶은 XML의 요소에 매핑하면 된다. 이 예제는 Listing 4와 같은 설정 파일이 있다고 가정한다.
Listing 4. Config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<datasource-name>IRIS</datasource-name>
<ipaddress>9.124.74.85</ipaddress>
<logfilename>DailyLogApplication.log</logfilename>
<appender>console</appender>
</config>
|
Listing 5는 설정 파일을 읽어 설정 값을 자바 객체로 불러오는 ConfigReader 클래스의 소스를 보여준다.
Listing 5. ConfigReader.java
package com.samples;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import com.thoughtworks.xstream.*;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class ConfigReader {
String datasourcename = null;
String ipaddress = null;
String logfilename = null;
String appender = null;
@Override
public String toString() {
//이 메서드는 멤버 변수의 값을 출력한다.
return "Datasource Name : "+datasourcename+
" \nIP Address : "+ipaddress+
" \nLogfilename : "+logfilename+
" \nAppender : "+appender;
}
/**
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
XStream xs = new XStream(new DomDriver());
FileInputStream fis = new FileInputStream("c:/temp/Config.xml");
xs.aliasField("datasource-name", ConfigReader.class, "datasourcename");
xs.alias("config", ConfigReader.class);
ConfigReader r = (ConfigReader)xs.fromXML(fis);
System.out.println(r.toString());
}
}
|
|
몇 가지 간단한 절차만 거치면 XStream을 설치하고 응용 프로그램을 개발할 수 있다. 이 기사를 통해 XStream을 사용하여 자바 객체를 직렬화하고, 역직렬화하고, 설정 파일을 읽는 방법을 배웠으니 XStream 사이트에서 앨리어스(alias), 어노테이션(annotation), 변환기(converter)에 대해 더 자세히 배울 수 있다(참고자료). 앨리어스와 변환기를 사용하면 생성되는 XML을 완전히 제어할 수 있다.
[출처] XStream으로 자바 객체를 XML로 직렬화하기 |작성자 마검린
자바 직렬화란 무엇인가?
자바에서는 자바에서 제공하는 기본적인 데이터 유형 이외에도 여러 객체들을 스트림에 쓰고, 읽을 수 있는 기능을 제공하는데 이것이 바로 객체 직렬화를 통해서 가능하다.
이러한 객체 직렬화 기법은 원격 메소드 호출, 보안 및 암호화 등 실제 프로그래밍 시에 유용하게 사용되어 질 수 있다.
객체 직렬화의 비밀
그러면 먼저 객체 직렬화가 어떠한 과정을 거쳐서 이루어 지는지 비밀을 벗겨보도록 하자.
먼저 객체들은 ObjectOutputStream에 의해서 직렬화가 되며, ObjectInputStream에 의해서 직렬화가 해제된다는 사실을 기억하도록 하자. 이러한 일련의 과정을 그림으로 나타내면 다음과 같다.
[그림 객체 직렬화]

여기에 사용되는 ObjectOutputStream과 ObjectInputStream은 모두 java.io 패키지의 일부분이고, 각각 DataOutput과 DataInput클래스를 implement한 ObjectOutput과 ObjectInput을 extends 해서 만들어 진것이다. 그리고 이 두 클래스에는 비원시 객체와 배열등을 스트림에 읽고 쓰기 위한 메쏘드들이 추가되어져 있다.
[그림 클래스 구조도]

객체 직렬화의 과정
지금부터는 보다 자세히 객체의 직렬화 과정에 대해 알아보도록 하자.
객체는 ObjectOutputStream의 writeObject() 메쏘드에 자신을 넘김으로써 직렬화 된다.
WirteObject()메쏘드는 private 필드와 super 클래스로부터 상속받은 필드를 포함, 객체의 모든 것을 기록하게된다.
직렬화 해제는 직렬화와 반대의 과정을 거치게 되는데 ObjectInputStream의 readObject()메쏘드를 호출함으로써 스트림으로부터 읽어 들이고 이를 직렬화가 되기전의 객체로 다시 만들게 된다.
다음은 객체가 직렬화 되고 해제되어 원래의 객체로 복원되는 과정에 대한 간단한 예제이다.
눈여겨 볼 부분은 ObjectInputStream을 생성해서 writeObject()를 사용해서 객체를 직렬화 하는것과 ObjectInputStream을 생성해서 readObject()를 통해서 객체를 복원하는 부분이다. 또한 SerializableClass가 Serializable을 implements한 것을 주의해서 보길 바란다.
|
import java.io.*; public class ObjectSerializeTest { public static void main(String[] args) throws Exception { // 객체 스트림을 열고, 객체스트림을 통해 객체를 파일에 저장 // 스트림을 닫는다. /* 직렬화 된 객체가 저장된 파일로 부터 객체를 해제시켜 원래의 객체를 복원*/ // 객체 입력 스트림으로부터 객체를 읽어온다. // 스트림을 닫는다. /* 스트림으로부터 읽어들인 객체의 내용을 출력 원래 생성되었던 객체와 같은 값을 갖는다는 것을 알수가 있다. */ /* 하나의 문자열과 정수를 저장하고있는 클래스 class SerializableClass implements Serializable { public String mString; // 생성자
String : Serialize Test Program
|
커스텀 직렬화
- Serializable
스트림을 통해서 직렬화 또는 해제 될수 있는 객체는 Serialiazable을 implements한 객체만이 가능하다.자바 2에서는 java.awt, javax.swing, etc등의 클래스들이 Serializable을 implements하고 있으며, 이러한 상위 클래스들이 implements하므로 하위 클래스들 또한 같이 직렬화/해제의 범주에 들 수가 있다.
다음은 Serializable을 implements하고있어서 객체의 직렬화가 가능한 객체들의 리스트이다.
[직렬화 가능 객체 리스트]
|
패키지 |
Serializable |
|
java.awt |
BorderLayout, CardLayout, CheckboxGroup, Color, Component, ComponentOrientation, Cursor, Dimension, Event, FlowLayout, FocusManager, Font, FontMetrics, GraphicsConfigTemplate, GridBagConstraints, GridBagLayout, GridBagLayoutInfo, GridLayout, ImageMediaEntry, Insets, LightweightDispatcher, MediaTracker, MenuComponent, MenuShortcut, Point, Polygon, Rectangle, ScrollPaneAdjustable, SystemColor |
|
java.awt.dnd |
DropTarget |
|
java.awt.font |
TransformAttribute |
|
java.awt.geom |
AffineTransform |
|
java.awt.image.renderable |
ParameterBlock |
|
java.beans |
PropertyChangesSupport, VetoableChangeSupport, BeanContext, BeanContextChildSupport, BeanContextSupport |
|
java.io |
ExternalizableFile, FilePermission, FilePermissionCollection, ObjectStreamClass |
|
java.net |
InetAddress, SocketPermission, SocketPermissionCollection, URL |
|
java.rmi |
MarshalledObject |
|
java.rmi.activation |
ActivationDesc, ActivationGroupDesc, ActivationGroupID, ActivationID |
|
java.rmi.dgc |
Lease, VMID |
|
java.rmi.server |
ObjID, RemoteObject, UID |
|
java.security |
AllPermissionCollection, BasicPermission, BasicPermissionCollection, CodeSource, GuardedObject, Identity, Key, KeyPair, Permission, PermissionCollection, Permissions, PermissionsHash, SecureRandomSpi, SignedObject, UnresolvedPermission, UnresolvedPermissionCollection |
|
java.text |
BreakIterator, Collector, DateFormatSymbols, DecimalFormatSymbols, Format, SpecialMapping, TextBoundaryData, UnicodeClassMapping, WordBreakTable |
|
java.util |
ArrayList, BitSet, Calendar, Date, EventObject, HashMap, HashSet, Hashtable, LinkedList, Locale, PropertyPermissionCollection, Random, TimeZone, TreeMap, TreeSet, Vector |
|
javas.swing.table |
AbstractTableModel, DefaultTableCellRenderer, DefaultTableColumnModel, DefaultTableModel, TableColumn |
|
javax.swing.text |
AbstractDocument, EditorKit, GapContext, SimpleAttributeSet, StringContent, StyleContext, TabSet, TabStop |
|
javax.swing.tree |
DefaultMutableTreeNode, DefaultTreeModel, DefaultTreeSelectionModel, TreePath |
Serializable은 Cloneable과 같은 마커 인터페이스로서, 어떠한 메쏘드들을 정의해놓은 것이 아닌, serizlVersionUDI라는 변수 하나만을 가지며, 이 객체가 직렬화가 가능하다는 것을 알려주는 역할만을 하는 인터페이스일 뿐이다.
- transient
스트림을 이용해서 직렬화 하는데 있어서, 커다란 프로그램 전체가 직렬화된다면, 여러가지 면에서 많은 낭비일 것이다. 예를 들어, 한 객체가 마우스가 눌려진 위치를 알기 위해서 마우스 클릭시에 위치를 저장하는 필드를 가지고 있다고 가정하자, 이 경우 마우스의 위치값은 프로그램이 돌아가는 상태에서 마우스가 눌려졌을 당시에만 유효한 값으로, 객체가 직렬화 되었다가 해제 되었을 경우에는 쓸모없는 값이 되어버린다.
이런 객체 직렬화에 쓸모없는 값들은 transient로 선언해 줌으로써 객체 직렬화에서 제외되어질수 있다.
- Private transient int x;
이러한 선언은 플랫폼에 따라 다른 값을 가지는 필드나, 현재의 환경에서만 유효한 필드등을 객체 직렬화에서 제외하는데 유용하게 쓰일 수가 있다.
transient선언이 적용된 예이다.
|
import java.io.*; public class ObjectSerializeTest1 extends TestClass implements Serializable { // 변수 선언, x는 객체직렬화에서 제외되도록 transient로 선언 // 생성자 Serializable을 implements한 i와 x는 받아온 인자를 그대로 대입하고, TestClass를 extends한 j는 /* 객체직렬화를 하기전의 객체의 값들을 알아본뒤에, 해당 객체를 스트림에 직렬화 시킨다.*/ /* 스트림으로 부터 객체를 해제시킨다. */ /* 객체의 값을 알기 위해서 오버라이드 */ public static void main(String[] args) throws Exception { // 객체를 생성시킨뒤, 스트림에 객체를 쓴다.(10은 transient로 선언된 필드의 값임을 유의) // 정보를 저장한 화일을 열고 스트림을 통해 읽은뒤 객체직렬화를 해제시킨다. // print문 수행시 형 변환이 이루어져서 이미 오버라이드된 toString()메쏘드가 수행된다. /* Serialize되지 않은 클래스 객체 직렬화 작업으로부터는 제외, 만약 사용자가 이 클래스를 객체 직렬화에 사용하고 싶다면 Serializable을 implements하면 된다. 만약 그렇게 할수 없을 경우에는 위와 같이 하도록 한다. */
writeObject
|
- externalizable
객체직렬화의 또 다른 방법으로는 Externalizable 인터페이스를 들수 있는데, 이 방법은 Serializable보다 더 강력하게 객체 직렬화를 제어하고 싶을 경우에 사용되어진다. 어떤 클래스가 이 인터페이스를 구현하게 되면 readExternal()과 writeExternal()메쏘드를 사용하여 객체를 스트림으로부터 읽고 쓸수있다. Externalizable객체들은 자신의 상태를 직렬화 및 해제하는 과정에서 강력한 제어를 할수 있으며, Serializable 객체에서의 기본 데이터 포멧을 사용하고싶지 않을때에 사용한다.
다음은 externalizable을 사용한 객체 직렬화의 예이다.
|
import java.io.*; public class ObjectExternalizeTest int i; /* 인자없는 생성자(직렬화된 데이터를 읽어들여서 객체를 만들기 위해 필요) */ /* 생성자 */ /* readObject()메쏘드로부터 호출이 되며, 직렬화된 객체를 해제시킨다. */ /* writeObject()메쏘드로부터 호출이 되며, 변수들을 직렬화한다.*/ /* 변수들의 값을 보여준다.*/ public static void main(String[] args) throws Exception { // 객체가 직렬화되어 저장된 파일로부터 스트림을 얻어온다. // 객체 직렬화 이전의 객체와 직렬화를 거친 뒤 다시 해제된 객체의 값을 출력한다.
Execute writeExternal() 1000, Externalizable Test
|
애플릿 직렬화
객체직렬화는 애플릿을 직렬화하는데에도 사용이 되어진다. 이러한 경우 <Applet>태그는 클래스 파일 대신에 직렬화 된 객체 파일을 지정하게 되고, 브라우저는 이러한 태그를 만나면 직렬화된 애플릿을 해제하여 화면에 보여주게 된다. 즉, 그래픽 유저 인터페이스를 생성하기 위한 코드를 전혀 가지고 있지 않으면서도 완벽한 그래픽 유저 인터페이스를 가지게 되는것이다.
일반적으로 직렬화된 애플릿은 *.ser의 확장자를 가진다.
직렬화된 애플릿을 호출하는 html 파일은 다음과 같은 내용을 가진다.
- <Applet Object="SerializableApplet.ser" Width=300 Height=300></Applet>
소켓을 통한 객체 직렬화
소켓을 생성한 뒤 스트림을 얻어서 ObjectInputStream과 ObjectOutputStream을 얻어서 사용한다면, 파일이 아닌 네트웍 너머의 다른 컴퓨터와도 객체를 직접 주고 받을수 있다.
소켓을 통해 직렬화 되어 쓰고 읽혀질 객체는 역시 Serializable을 구현하고 있어야 하며, 사용법은 파일에 쓰고 읽는것과 동일하다.
다음은 서버에서 이미지를 포함하고 있는 Serializable을 구현한 객체를 생성하여 소켓을 이용하여 클라이언트 애플릿에게 직렬화된 객체를 보내고, 애플릿에서는 이를 해제하여 화면에 나타내는 예제이다.
여기서 주의깊게 살펴보아야 할 점은 이미지를 직렬화하기위한 방법이다.
이미지는 Serializable을 구현하고 있지 않기 때문에 직접적으로 객체 직렬화에 사용되어질 수는 없다. 하지만, 자바 2에서는 배열을 직렬화에 사용할 수가 있고, 이미지는 각각의 픽셀들이 배열에 저장되어질수 있으므로 직접적으로 이미지를 직렬화 할 수는 없지만 배열을 사용하여 간접적으로나마 이미지를 객체 직렬화에 사용할 수가 있다.
- 서버측 프로그램
|
import java.awt.*; public class ImageSerializeServer { // 서버는 3434 포트로 임의로 설정 // ImageSerializeServer를 실행한다. /* 생성자. 서버의 소켓을 생성하고 클라이언트의 연결을 대기 */ // 포트를 지정(3434) // 지정된 포트로 서버의 소켓을 생성한다. // 클라이언트의 연결을 대기 /* 클라이언트로 부터의 연결을 기다리면서 무한루프를 돈다. */ // 클라이언트로 부터의 연결이 요청되면 클라이언트의 소켓을 생성 하고 이미지 픽셀을 클라이언트로 보내는 쓰레드를 생성한다. /* 간단한 이미지를 이루는 픽셀을 만들어 이를 네트웍너머의 클라이언트로 보내는 클래스 */ // 변수 선언 // 간단한 이미지 픽셀 public appletConnection (Socket client) { // 객체 직렬화를 위한 출력 스트림을 생성 public void run () { /* Serializable을 구현한 imagePixel객체를 생성해서 Vector에 집어넣는다. 따라서 이미지가 하나가 아닌 여러개 일지라도 객체 직렬화를 통해 전달하는것이 가능하다.*/ // 이미지 픽셀들을 포함하고 있는 벡터를 객체 직렬화 시켜 스트림에 쓴다. /* 객체의 직렬화를 위해 Serializable을 구현한 imagePixel 클래스 */ // 생성자
|
- 클라이언트측 프로그램
|
import java.applet.*; public class ImageSerializeClient extends Applet { // 기본 포트는 서버와 같이 3434로 하고 host는 localhost로 설정한다. // 변서 선언 public void init() { /* 서버에 접속하여 소켓을 구한뒤에 객체 직렬화를 해제하기 위한 스트림을 얻는다. 이것은 마치 파일로부터 스트림을 얻는 과정과 비슷하다. */ public void start() { // 객체를 스트림으로 부터 읽어들여 직렬화를 해제한다. // 직렬화가 해제된 객체는 Vector에 들어가게 되고 Vector의 요소인 imagePixel을 구한다. // 이렇게 구해진 imagePixel의 이미지 픽셀을 가지고 실제 이미지를 생성 // 생성된 이미지로 그림을 그린다.
|
- 애플릿 포함 Html 내용
|
<HTML> <APPLET CODE = "ImageSerializeClient.class" WIDTH = 100 HEIGHT = 100 ></APPLET> </BODY>
|
- 최종 결과 화면

프로그램을 실행하기 위해서는 다음의 과정으로 실행하면 된다.
- 서버측 프로그램인 ImageSerializeServer.java를 컴파일하고, 서버 쪽에서 실행시면, "Server Running..."이라는 메시지가 나타나면서 서버측 프로그램이 제대로 작동을 하는 것이다.
- 다음으로는 클라이언트 애플릿 프로그램인 ImagSerializeClient.java를 컴파일한다.
- 브라우져를 실행시킨뒤에 클라이언트 애플릿 클래스를 실행시키기 위한 html파일이 있는 URL주소를 주소 입력란에 넣는다.
- 이때 서버프로그램이 돌아가는 곳과 애플릿을 위한 코드 및 html파일이 위치한 곳은 같은 Machine상에 있어야 한다.
참고로 이번 예제에서는 이미지 픽셀을 직접 그 값을 대입해서 이미지를 대신했는데, 실제 이미지를 이미지 픽셀로 바꾸는 기능이 자바에서 지원되고 있으므로 이를 간단히 소개토록 하겠다.
이미지는 여러개의 색깔을 표현하고 있는 픽셀들의 집합으로 볼 수 있고, 보다 정교하게 이미지를 다루는 작업을 하고 싶다면, 이미지의 픽셀들을 얻어서 조작을 해야한다. 그렇다면 어떻게 이미지의 픽셀들을 얻을 수 있을까? 그것은 PixelGrabber를 통해서 가능하다.
PixelGrabber는 이미지와 해당 이미지의 정보들을 기반으로 이미지 픽셀을 구해준다.
다음은 실제로 이러한 것을 보여주는 코드이다.
|
. /* imageObject로부터 픽셀들을 얻어서 imagePixel배열에 저장한다. */ imagePixel = new int[imageWidth * imageHeight]; // imagePixel을 초기화 한다. // grabber를 생성해서 픽셀들을 얻는다. if((grabber.status() & ImageObserber.ABORT) != 0) |
참고 문헌
- Java Examples In a Nutshell (O'RELLY)
- Java I/O (O'RELLY)
[출처] 객체 직렬화의 비밀..|작성자 원민아빠
웹로직 시작시 InvalidClassException 오류가 발생한다면
- Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0 추가
2. ant task 수행 중 다음과 같이 ANT_OPT를 설정한다.
Set ANT_OPT=-Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0
3. 모든 ANT 파일의 java 혹은 javac 작업에서 jvmarg를 아래 샘플처럼 적용하라.
<target name="run">
<java classname="examples.webservices.jws_basic.simple.Client" fork="true"
failonerror="true" >
<!--Note the jvmarg tag -->
<jvmarg line="-Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0" />
<classpath refid="client.class.path"/>
<arg line="http://${wls.hostname}:7001/jws_basic_simple/SimpleService" />
</java>
</target>



