2011-11-14

wrapper class

//==============================================================

자료형의 효율적인 관리와 자료형은익화를 위해 만들어진 자료형 대체 클래스이다.
OOP의 개념중에 은닉화라는 개념이 있는데 숨길수 있는것은 최대한 숨기자는 뜻.

(Infomation Hiding Encapsulation
내부의 데이타는 외부로 부터 고립되었다. 데이타는 필요한 때에 단지 외부로부터의 Message에 의해서만
접근되어질 수 있는데, 이러한 것을 정보 은닉이라 한다. 만약 Object내의일부분을 수정하였다고 해도
그 변화는 단지 Object내에서만 영향을 끼치고, 이로 인하여 완전히 모듈화가 이루어지는 것이다.)

그러나 숨겨도 그형태를 쉽게 알아볼수 있는 타입이 있는데 바로 기본 자료형이다.(메모리의 바이트수만보면 대충짐작이 가능)
그래서 완벽한 은닉화를 위해 기본자료형을 대체할 class를 만들었고 이를 wrapper class라 한다.
wrapper class는 메모리를 보면 모두 4byte로 보이게 된다.

boolean => Boolean
char => Character
byte => Byte
short => Short
int => Integer
long => Long
float => Float
double => Double

import방법은 import java.lang.*;

//===========================================================================정의

1. Integer클래스

ex)
public class Test{
public static void main(String[] args) {
String str = "2147483648";
int x = Integer.parseInt(str);
x+=2;
System.out.println(x);
}
}
만약 문자로 위와같은 숫자를 받았을경우 10진수가 아닌 다른수로 어떻게 변환할까? int형으로 캐스팅 후
계산해도 되겠지만 수가 커질수록 당혹스러울것이다. 불편할것이다. 그래서 wrapper class가 필요한것이다.



2. 오토박싱, 오토언박싱

JDK 5.0에서 지원하는 방식
오토박싱 : 값형식 변수인 기본 자료형이(int....) 레퍼언스 형식 변수인 wrapper 클래스형(Interger)으로 변환하는것.
스택상의 메모리 공간에 있던 값을 힙상의 객체를 생성하여 복사하는것
오토언박싱 : 오토박싱과는 반대로 힙영역을 스택영역으로 복사하는것

1.4에서는 xxxValue()메소드를 이용해서 변환했지만 1.5부터는 바로 변환이 가능해졌다.

ex1)
Integer object = new Integer(12000); //오토박싱
int num = object.intValue(); //오토언박싱

ex2)
public class Test {

public static void main(String[] args) {
new Test().testInteger();
}
public void testInteger() {
int a = 1;
int b = 1;
Integer c = new Integer(1);
Integer d = new Integer(1);

System.out.println("1번 a == b : "+(a == b)); //true
System.out.println("2번 c == d : "+(c == d)); //false
System.out.println("3번 c.equals(d) : "+c.equals(d)); //true
System.out.println("4번 a == c : "+(a == c)); //true 오토언박싱이 되면서 wrapper class의 값을 꺼내어
//프리미티브타입으로 변형
//================================================================
String q = "TEST";
String w = "TEST";
String e = new String("TEST");
String r = new String("TEST");

System.out.println("5번 q == w :"+(q == w)); //true
System.out.println("6번 q.equals(w) :"+q.equals(w)); //true
System.out.println("7번 e == r :"+(e == r)); //false
System.out.println("8번 e.equals(r) :"+e.equals(r)); //true
}
}



3. Long 클래스

ex)
class Test{
public static main(String[] args){
Long num = new Long(10);
String strN = "10";
}
}
//parsexxx : 문자열에 해당하는 값을 해당 기본 자료형으로 변경한다.
long ss = Long.parseLong(strN);

//문자열에 해당되는 값을 해당 Wrapper클래스형 객체로 변경한다.
Long num2 = long.valueOf(strN);



4.Character 클래스

Character.isDefined(문자데이터) :문자데이터가 유니코드 이면true
Character.isDigit(문자데이터) :문자데이터가 숫자 이면true
Character.isLetter(문자데이터) :문자데이터가 문자이면true
Character.isLetterOrDigit(문자데이터) :문자데이터가 숫자나 문자이면true
Character.isLowerCase(문자데이터) :문자데이터가 소문자 이면true
Character.isSpace(문자데이터) :문자데이터가 공백 이면true
Character.isUpperCase(문자데이터) :문자데이터가 대문자 이면true
Character.toLowerCase(문자데이터) :문자데이터를 소문자로 변형
Character.toUpperCase(문자데이터) :문자데이터를 대문자로 변형


//=====================================wrapper class는 언제 써야하는가?

1 기본 데이터 타입을 객체로 혹은 다른 타입으로 변환을 위한 목적
2 wrapper class를 이용하지 않고도 자료형간의 변환은 가능하나 간단하고 직관적인 경우,
굳이 wrapper class를 쓰지 않고 그냥 구현하는 것이 더 빠를 수 있다.
허나 가독성면에서 wrapper class를 사용하면 깔끔해지므로 wrapper class를 사용하는게 낫다고 생각된다.
3 내부구조나 동작을 감추거나 편의를위해 인터페이스를 제한하기위한 도구로 활용.

2011-11-13

톰캣 한글 파라메터 설정

웹개발을 하면서 한글은 매우 어려운 문제입니다. 제 경우에는 한글 문제만큼은 단기 학습을 통해서 해결이 되지 않았습니다. 온갖 문서를 읽어보고 실험해보고 했지만 정확히 이해하는 것은 매우 힘들었습니다. 또한 조금 이해한 것 같으면 계속해서 새로운 문제가 등장하였습니다. 지금도 여전히 깊은 이해는 없다고 생각합니다. 하지만 경험을 정리하면 누군가에게는 도움이 될수도 있으리란 기대에 내용을 정리해봅니다.

1. 서버 측면에서 POST와 GET의 처리의 차이점

저는 POST로 보내든 GET으로 보내든 request.setCharacterEncoding(CHARSET)만 호출해주면 자바 내에서의 한글처리는 완료된다고 알고 있었습니다. 하지만 실제로는 그렇지 않았습니다. request.setCharacterEncoding(CHARSET)는 POST방식에만 유효합니다. GET방식의 캐릭터셋 정의는 톰캣의 경우 server.xml의 Connector 설정쪽에 URIEncoding라는 옵션을 통해서 가능합니다. 이 옵션에 캐릭터셋을 정의하게 되면 GET방식으로 오는 파라메터에 대해서 해당 캐릭터셋을 이용하여 디코딩을 합니다.(만약 지정되어 있지 않다면 ISO-8859-1을 기본적으로 사용하게 됩니다.)

결론적으로 POST와 GET을 모두 정확하게 처리하려면 setCharacterEncoding뿐만 아니라 URIEncoding이 정의가 되어 있어야 합니다. 또한 GET방식은 브라우저에 따라서 자동으로 URL인코딩을 해주지 않는 경우가 있기 때문에 GET파라메터에 대해서는 항상 URL인코딩을 해주는 것이 좋을 것으로 보입니다.

2. 항상 setCharacterEncoding을 해주어야 하는 이유?

어느 순간 왜 항상 setCharacterEncoding을 해줘야 하는지에 대한 의문이 들었습니다. 송신측에서 내가 보내는 데이터가 어떤 타입인지 명시해주고 수신측에서 그 값에 따라 동적으로 처리해주면 좋을텐데라는 생각이 들었습니다. 처음에는 HTTP 해더를 살펴보면 뭔가 답이 있을 것이라 생각했습니다. 파이어폭스의 플러그인인 파이어버그를 이용하여 서버로 날아가는 HTTP 패킷을 살펴보았습니다. 비슷해 보이는 해더를 찾아볼 수가 없었습니다. HTTP RFC를 열심히 뒤져보았습니다. 그러나 요청에서 사용할 수 있는 해더 후보 목록 중에서는도무지 해당 내용을 찾아볼 수가 없었습니다. HTTP 1.1이 다국어에 대한 고려를 미처 하지 못해 지원이 안 되는구나라고 생각했습니다.

3. Connector의 useBodyEncodingForURI 옵션을 발견

그러던 중 톰캣의 useBodyEncodingForURI 라는 옵션의 명세를 보게됐습니다. 내용은 아래와 같았습니다.

http://tomcat.apache.org/tomcat-5.5-doc/config/http.html

This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitely set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false.

그 중 위 밑줄 처친 부분이 심상치 않게 느껴졌습니다. 분명히 "contentType안에 명시된 인코딩"이라고 하고 있습니다. contentType이라는 해더가 분명히 있을 것이라 생각하게 되었습니다.

4. Content-type=application/x-form-urlencoded;charset=UTF-8 발견

문제에 대해 여러 지인들에게 질문을 던지던 중 제 사수이시기도 했던 선배분이 톰캣 소스를 보고 HTTP 해더에 "Content-type=application/x-form-urlencoded;charset=UTF-8"과 같이 보내주면 setCharacterEncoding을 하지 않아도 UTF-8로 파라메터가 읽혀진다는 것을 알려주었습니다. 정말 테스트해보니 아무것도 정의하지 않고 getCharacterEncoding을 하니 UTF-8이 반환되었습니다.

5. 그렇다면 어떤 근거로?

처음 가졌던 의문에 대한 답은 된 셈이였습니다. 하지만 찝찝합니다. 어떤 근거로 톰캣이 이렇게 구현을 했는지가 궁금했던 것이였습니다. 이것 때문에 (나름대로는)많은 시간을 들여서 찾아본 결과 해당 내용에 대해 다룬 내용을 찾을 수 있었습니다.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.4

HTTP/1.1 uses many of the constructs defined for Internet Mail (RFC 822 [9]) and the Multipurpose Internet Mail Extensions (MIME [7]) to allow entities to be transmitted in an open variety of representations and with extensible mechanisms.
http://tools.ietf.org/html/rfc2045#section-5

The purpose of the Content-Type field is to describe the data contained in the body fully enough that the receiving user agent can pick an appropriate agent or mechanism to present the data to the user, or otherwise deal with the data in an appropriate manner. The value in this field is called a media type.
즉 HTTP에서 데이터(Entities) 전송을 위해 MIME 사용이 가능합니다. 그리고 그 중 Content-Type은 수신측이 우리가 보내는 데이터를 정확히 해석하는 것을 도와주기 위해 사용됩니다. 즉 Content-Type은 위의 "Content-type=application/x-form-urlencoded;charset=UTF-8" 와 같이 여러 가지 정보를 기술하기 위해 사용 될 수 있는 것입니다.

6. 남은 부분

하지만 아직까지 남아있는 궁금증이 있습니다. 그것은 바로 "브라우저에서 해더에 Content-Type을 함께 보내게 하려면 어떻게 해야하나"라는 문제입니다. 이 방법을 알게되면 서버에서 획일적으로 하는 setCharacterEncoding을 완전히 제거할 수 있습니다. 대신 톰캣은 해더에서 정보를 읽어 상황에 따라 적절하게 요청을 읽을 수 있을 것입니다. 이것은 블로그의 트랙백과 같은 기능에서 유용하게 이용될 수 있을 것 같습니다. 트랙백은 여러 서비스들에서 보내며 그들의 인코딩은 다양할 수 있기 때문입니다.

이 부분을 찾아내기 위해여 여러 테스트를 해보았으나 아직 찾지 못했습니다. 그래서 우선은 알아낸 부분까지 기록하고 나중에 이 문제와 관련한 또다른 지식이나 이해가 생기게 되면 계속해서 이 포스트에 정리해나가도록 하겠습니다.