관리 메뉴

버리야 날자

Jersey의 MessageBodyReader/Writer 본문

나만의 작업

Jersey의 MessageBodyReader/Writer

버리야 2009.06.03 10:19
JAX-RS는 MessageBodyReader와 MessageBodyWriter를 통해 HTTP 메세지 바디와 자바 타입간의 마샬링과 언마샬링을 해준다.

MessageBodyReader의 생긴 모습을 보면, (이 인터페이스를 구현하여 원하는 모습의 자바타입 객체로 변신시킬 수 있다.)

public interface MessageBodyReader<T> {
boolean isReadable(Class<?> type, Type genericType, 
            Annotation annotations[], MediaType mediaType);

T readFrom(Class<T> type, Type genericType,  
            Annotation annotations[], MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, 
            InputStream entityStream)
throws IOException, WebApplicationException;
    
}


<Message Body Reader>
representation을 자바 타입으로 매핑한다. 
MessageBodyReader 인터페이스 구현 필요, @Provider 어노테이션이 꼭 필요하다.

JSON representaion 예제
{"Customer ":{"id":"123","name":"john"}}
의 JSON타입이 들어오면 MessageBodyReader를 통해 
Customer라는 객체의 필드 id = 123, name = john의 자바타입으로 매핑을 시킬 수 있다.

단계
1. 엔티티 바디에 맞는 자바 타입 선택
2. 요청 미디어 타입에 맞는 MessageBodyReader 클래스 선택
3. isReadable 메소드를 이용해 선택한 MessageBodyReader 클래스를 돌아가며 원하는 자바 타입의 MessageBodyReader 프로바이더 선택
4. 3번이 성공하면, MessageBodyReader의 readFrom으로 바디를 자바 타입으로 매핑
3번이 실패하면, HTTP 415 상태코드(지원하지 않는 미디어 타입)로 응답 보냄.


 MessageBodyWriter를 살펴보면, (이 인터페이스를 구현하여 원하는 모습의 representation 타입 객체로 변신시킬 수 있다.)

public interface MessageBodyWriter<T> {
boolean isWriteable(Class<?> type, Type genericType,
            Annotation annotations[], MediaType mediaType);

long getSize(T t, Class<?> type, Type genericType,
Annotation annotations[], 
            MediaType mediaType);

void writeTo(T t, Class<?> type, Type genericType, 
Annotation annotations[], 
            MediaType mediaType, 
            MultivaluedMap<String, Object> httpHeaders,
            OutputStream entityStream) throws IOException,
WebApplicationException;    
}


<Message Body Writer>
자바 타입을 representation으로 매핑한다.
 MessageBodyWriter 인터페이스 구현 필요, @Provider 어노테이션이 꼭 필요하다.

단계
1. 응답 엔티티 바디로 매핑할 객체를 얻기
2. @Produces 값 얻기
3. MessageBodyWriter 프로바이더 집합 선택
4. 선택한 MessageBodyWriter 프로바이더 정렬
5. isWriteable 메소드를 이용해 선택한 MessageBodyWriter 프로바이더를 돌아가며 적합한 MessageBodyWriter 프로바이더 선택
6. 5번이 성공하면, writeTo 메소드로 객체를 엔티티 바디로 매핑
5번이 실패하면, HTTP 406 상태코드(요청한 페이지가 요청한 콘텐츠 특성으로 응답할 수 없습니다)로 응답 보냄


꼭 필요한 annotation
MessageBodyReader -> @Consumes
MessageBodyWriter -> @Produces
각 클래스는 맞는 annotation을 사용해야 한다.



MessageBodyReader를 구현한 테스트 클래스

package com.flyburi.jersey.resources;


import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

import com.flyburi.jersey.model.User;
import com.sun.jersey.api.spring.Autowire;

@Consumes(MediaType.APPLICATION_JSON)
@Provider
@Autowire
public class UserReader implements MessageBodyReader<User>{

private final Log logger = LogFactory.getLog(getClass());
@Override
public boolean isReadable(Class<?> klass, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return User.class.isAssignableFrom(klass);
}

@Override
public User readFrom(Class<User> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream in)
throws IOException, WebApplicationException {
String body = IOUtils.toString(in);
User user = null;
try {
JSONObject json = new JSONObject(body);
String id = json.getString("id");
String name = json.getString("name");
String password = json.getString("password");

user = User.create(id, name, password);
} catch (JSONException jse) {
if (logger.isErrorEnabled()) {
logger.error(jse);
}
}
return user;
}

}



MessageBodyWriter를 구현한 테스트 클래스

package com.flyburi.jersey.resources;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jettison.json.JSONObject;

import com.flyburi.jersey.model.User;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class UserWriter implements MessageBodyWriter<User>{

private static final String JSON_EMPTY_CONTAINER = "{}";
private final Log logger = LogFactory.getLog(getClass());
@Override
public long getSize(User t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}

@Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return User.class.isAssignableFrom(type);
}

@Override
public void writeTo(User user, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream output) throws IOException,
WebApplicationException {
JSONObject json;
try {
json = new JSONObject(JSON_EMPTY_CONTAINER);
json.accumulate("id", user.getId());
json.accumulate("name", user.getName());
json.accumulate("password", user.getPassword());
output.write(json.toString().getBytes());
} catch (Exception ex) {
logger.error(ex);
}
}

}



'나만의 작업' 카테고리의 다른 글

[Jersey] Representation and Java Types  (0) 2009.07.16
Jersey의 JSON Support  (2) 2009.06.08
Jersey의 Exception Handling  (0) 2009.06.05
Jersey의 Return Type  (0) 2009.06.04
Jersey의 MessageBodyReader/Writer  (1) 2009.06.03
JAX-RS @Produces와 @Consumes  (2) 2009.06.02
JAX-RS의 구성  (0) 2009.06.01
What is Jersey?  (0) 2009.06.01
What is JAX-RS?  (0) 2009.05.29
1 Comments
댓글쓰기 폼