직렬화를 위해 Jersey의 JSON/JAXB를 재사용하는 방법은 무엇입니까?
문제
저지를 사용하여 구현 된 JAX-RS REST 서비스가 있습니다. Jax -Rs/Jersey의 멋진 특징 중 하나는 Pojo가 JaxB 주석을 사용하여 Pojos를 JSON으로 변환하는 사소한 쉬운 메커니즘을 포함하여 몇 가지 Java 주석을 뿌려 휴식 서비스로 쉽게 바꿀 수 있다는 것입니다.
이제는이 멋진 JSON- 이용 기능을 비 레스트 목적으로 활용할 수 있기를 원합니다. JSON 텍스트와 같이 이러한 객체 중 일부를 디스크로 직렬화 할 수 있기를 바랍니다. 다음은 직렬화하고 싶은 예제 jaxb 객체입니다.
@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {
public UserInfoImpl() {}
public UserInfoImpl(String user, String details) {
this.user = user;
this.details = details;
}
public String getUser() { return user; }
public void setUser(String user) { this.user = user; }
public String getDetails() { return details; }
public void setDetails(String details) { this.details = details; }
private String user;
private String details;
}
저지는 추가 정보없이 이들 중 하나를 JSON으로 바꿀 수 있습니다. 저지가 API 에서이 기능을 내 필요에 대해 노출했는지 궁금합니다. 지금까지 그것을 찾는 운이 없었습니다 ...
감사!
2009-07-09 업데이트: 나는 제공자 객체를 거의 내가 원하는 것을 정확히하십시오 :
@Context Providers ps;
MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
uw.writeTo(....)
... 이것은 객체를 모든 출력 스트림에 JSON으로 씁니다. 이는 나에게 완벽 할 것이지만 @Component 객체에서 @Context를 사용하여 제공자 객체 만 얻을 수 있습니다. 정기적으로 주석이없는 Pojo에서 액세스하는 방법을 아는 사람이 있습니까? 감사!
해결책
Jersey는 Mapped (), Badgerfish () 또는 Natural () 표기법을 사용하는지 여부에 따라 몇 가지 다른 프레임 워크를 사용합니다. 자연은 일반적으로 사람들이 원하는 사람입니다. 그리고 그것은 객체-> jaxb-> json에서 나오는 매우 우수한 (그리고 매우 빠른) 독립형 Jackson Json 프로세서를 사용하여 구현되었습니다. 그러나 Jackson은 또한 자체 JAX-RS 제공 업체를 제공하여 직접 개체-> JSON을 제공합니다.
실제로 그들은 심지어 JAXB 주석에 대한 지원을 추가했습니다. 살펴보십시오
http://wiki.fasterxml.com/jacksonjaxbannotations
나는 그것이 궁극적으로 당신이 찾고있는 것이라고 생각합니다. Jackson은 Object <-> JSON 처리 ... Jersey는 당신을 위해 전화를합니다.
다른 팁
JaxB를 사용하여 객체를 JSON (Jackson 사용)에 매핑하는 간단한 간단한 예는 다음과 같습니다.
http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-jackson-howto.texy
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
JAXB 주석은 XML로 직렬화 할 때 정상적으로 작동합니다. 주요 문제는 JAXB가 빈 배열을 지원하지 않는다는 것입니다. 그래서 이와 같은 것을 직렬화 할 때 ...
List myArray = new ArrayList();
... JaxB anottations를 통해 JSON에게 모든 빈 배열은 [] 대신 무효가됩니다.
이를 해결하려면 Pojos를 Jackson을 통해 JSON으로 직접 직렬화 할 수 있습니다.
Jersey의 사용자 안내서에서 이것을 살펴보십시오.http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959
이것은 JAXB없이 Jackson 제공 업체를 사용하는 가장 좋은 방법입니다. 또한 웹에서 Jackson-All-Xyz-Jar를 다운로드하여 항상 최신 버전의 Jackson을 사용할 수 있습니다.
이 방법은 JAXB 주석을 방해하지 않으므로 시도해 볼 것을 제안합니다!
Jersey는 JAX-RS의 참조 구현이며 JAX-RS는 REST 서비스의 엔드 포인트를 구현하는 표준 방법을 제공하는 데 전적으로 중점을두고 있습니다.
JAX-RS 표준에 객체 직렬화를 포함하면 빠르게 중점을두고 풀기 어려운 큰 다중 머리 짐승이 될 것이라고 생각합니다.
깨끗하고 간단한 휴식 엔드 포인트를 전달하는 데 집중된 저지가 얼마나 감사하는지 감사합니다. 제 경우에는 모든 JAXB 배관이있는 부모를 서브 클래스하여 바이너리와 XML 사이의 마샬링 객체가 매우 깨끗합니다.
작은 저지 특정 부트 스트랩을 사용하면 필요한 JSON 객체를 만들 수 있습니다. 다음 종속성을 포함해야합니다 (번들을 사용할 수 있지만 테스트를 위해 용접을 사용하는 경우 문제가 발생합니다) :
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.12</version>
</dependency>
거기에서 JaxB 주석이 달린 클래스를 만들 수 있습니다. 다음은 예입니다.
@XmlRootElement
public class TextMessage {
private String text;
public String getText() { return text; }
public void setText(String s) { this.text = text; }
}
그런 다음 다음 단위 테스트를 만들 수 있습니다.
TextMessage textMessage = new TextMessage();
textMessage.setText("hello");
textMessage.setUuid(UUID.randomUUID());
// Jersey specific start
final Providers ps = new Client().getProviders();
// Jersey specific end
final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {
@Override
public void add(final String key, final Object value) {
}
@Override
public void clear() {
}
@Override
public boolean containsKey(final Object key) {
return false;
}
@Override
public boolean containsValue(final Object value) {
return false;
}
@Override
public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
return null;
}
@Override
public List<Object> get(final Object key) {
return null;
}
@Override
public Object getFirst(final String key) {
return null;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Set<String> keySet() {
return null;
}
@Override
public List<Object> put(final String key, final List<Object> value) {
return null;
}
@Override
public void putAll(
final Map<? extends String, ? extends List<Object>> m) {
}
@Override
public void putSingle(final String key, final Object value) {
}
@Override
public List<Object> remove(final Object key) {
return null;
}
@Override
public int size() {
return 0;
}
@Override
public Collection<List<Object>> values() {
return null;
}
};
final MessageBodyWriter<TextMessage> messageBodyWriter = ps
.getMessageBodyWriter(TextMessage.class, TextMessage.class,
new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
Assert.assertNotNull(messageBodyWriter);
messageBodyWriter.writeTo(textMessage, TextMessage.class,
TextMessage.class, new Annotation[0],
MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
final String jsonString = new String(baos.toByteArray());
Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));
이 접근법의 장점은 JEE6 API 내의 모든 것을 유지하는 것입니다. 테스트 및 제공자를 얻는 것 외에는 외부 라이브러리가 명시 적으로 필요하지 않습니다. 그러나 표준에 제공되지 않으므로 실제로 사용하지 않기 때문에 MultivaluedMap의 구현을 만들어야합니다. 그것 5월 또한 GSON보다 느리고 필요보다 훨씬 더 복잡합니다.
XML 뷰를 이해하지만 표준 장비로 Pojos에 대한 JSON 지원을 요구하는 것이 일부 예측을 보여 주었을 것입니다. 구현이 JSON이고 클라이언트가 JavaScript RIA 인 경우 특수 캐릭터를 가진 JSON 식별자를 닥터 해야하는 것은 의미가 없습니다.
또한 자바 콩이 Pojos가 아닙니다. 웹 계층의 외부 표면에서 이와 같은 것을 사용하고 싶습니다.
public class Model
{
@Property height;
@Property weight;
@Property age;
}
기본 생성자, getter/setter 노이즈, 내 자신의 주석이있는 포조.