2014-10-24 3 views
1

저지 엔드 포인트에 대한 json POST의 메시지 본문으로 org.joda.time.DateTime을 전달하고 싶습니다. My Jersey는 MOXy를 사용합니다. 이 작업을 수행하기 위해 사용자 지정 XmlAdapter를 만들었지 만이 어댑터를 연결하는 방법이 명확하지 않습니다. 사용자 지정 어댑터에서 찾은 예제는 내가 게시 할 수없는 개체에 주석을 사용합니다 (소스 코드를 조작 할 수 없어서 DateTime 클래스에 주석을 추가 할 수 없습니다).Jersey DateTime 오브젝트를 HTTP POST의 메시지 본문으로 Jersey REST 엔드 포인트에 전달하는 방법은 무엇입니까?

저는 이것을 테스트하기 위해 Jersey 테스트 프레임 워크를 사용하고 있습니다.

내 뉴저지 엔드 포인트 :

@POST 
@Path("/{memberId}") 
@Produces(MediaType.APPLICATION_JSON) 
@Consumes(MediaType.APPLICATION_JSON) 
public ResultBean recordDate(@PathParam("memberId") Long memberId, DateTime dateTime) { 
    // TODO stuff happens 
    return new ResultBean(memberId, dateTime); 
} 

내 뉴저지 테스트 :

public class FooEndpointImplTest extends JerseyTest { 

@Test 
public void testWithDate() { 
    Long memberId = 1L; 
     DateTime date = new DateTime(); 
     Entity<DateTime> dateEntity = Entity.json(date); 
     ResultBean result = target(
       "/" + memberId) 
       .request().post(dateEntity, ResultBean.class); 
     assertNotNull(result); 
    } 
} 

그리고 내 어댑터를 그대로 내가이 테스트를 실행하면

package foo; 

import javax.xml.bind.annotation.adapters.XmlAdapter; 

import org.joda.time.DateTime; 

public class DateTimeAdapter extends XmlAdapter<String, DateTime> { 

    @Override 
    public DateTime unmarshal(String v) throws Exception { 
     Long millis = Long.parseLong(v); 
     return new DateTime(millis); 
    } 

    @Override 
    public String marshal(DateTime v) throws Exception { 
     return Long.toString(v.getMillis()); 
    } 

} 

, 나는 500 오류 .

+0

무엇이 오류입니까? 스택 추적을 보여 주시겠습니까? –

답변

1

첫 번째 사항 먼저 : joda DateTime에 MessageBodyReader/Writer이 필요합니다.

일부 조정을하지 않으면 JSON 직렬화 된 DateTime의 POST가 작동하지 않습니다. >iChronology기본 비 - 인수 생성자, GSON 필요가 없습니다 - 당신이 GSON와 함께 다시 역 직렬화 할 경우, GSON이 실패합니다

{ "iMillis": 1414507195233, 
    "iChronology": { 
    "iBase": { 
     "iBase": { 
      ... 
     }, 
     "iParam": { 
      ... 
     }}}} 

org.joda.time.Chronology가 있기 때문에, :하는처럼 GSON 직렬화 된 날짜 시간 모양 객체를 직렬화 복원합니다. Afaig, 표준 디시리얼라이저를 사용하여 DateTime을 비 직렬화하는 동안 이러한 문제가 발생합니다.

그래서 나는 FasterXML/jackson-datatype-joda

리더를 기반으로 MessageBodyReader/라이터을 만드는 결국했습니다

// ... 
import org.joda.time.DateTime; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.datatype.joda.JodaModule; 

@Consumes(MediaType.APPLICATION_JSON) 
public class JodaTimeBodyReader implements MessageBodyReader<DateTime> { 

    private static ObjectMapper mapper = new ObjectMapper(); 

    public JodaTimeBodyReader() { 
     mapper.registerModule(new JodaModule()); 
    } 


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

    @Override 
    public DateTime readFrom(Class<DateTime> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { 
     try { 
      return mapper.readValue(entityStream, DateTime.class); 
     } catch (Exception e) { 
      throw new ProcessingException("Error deserializing a org.joda.time.DateTime.", e); 
     } 
    } 

} 

저자 : 모두 ResourceConfig에 등록

// ... 
import org.joda.time.DateTime; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.datatype.joda.JodaModule; 

@Provider 
@Consumes(MediaType.APPLICATION_JSON) 
public class JodaTimeBodyWriter implements MessageBodyWriter<DateTime> { 

    private static ObjectMapper mapper = new ObjectMapper(); 

    public JodaTimeBodyWriter() { 
     mapper.registerModule(new JodaModule()); 
    } 

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

    @Override 
    public long getSize(DateTime t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     // deprecated by JAX-RS 2.0 and ignored by Jersey runtime 
     return 0; 
    } 

    @Override 
    public void writeTo(DateTime t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { 
     try { 
      entityStream.write(mapper.writeValueAsBytes(t)); 
     } catch (Exception e) { 
      throw new ProcessingException("Error serializing a org.joda.time.DateTime to the output stream", e); 
     } 
    } 

} 

.

Writer는 1414507195233 (yap, JSON이 아님)으로 응답하고 리소스를 POST로 돌려 보내면 올바른 DateTime을 받게됩니다.

위 예제와 같이 JSON을 얻으면 Reader를 업그레이드하여 iMillis 용 JSON을 구문 분석하고 Long 값을 사용할 수 있습니다. TimeZone의 경우 동일한 작업을 수행하고 dateTime.withZone(...)을 사용하여 값을 설정할 수 있습니다. 내가 사용했던

메이븐 의존성 :

<dependency> 
    <groupId>joda-time</groupId> 
    <artifactId>joda-time</artifactId> 
    <version>2.5</version> 
</dependency> 

<dependency> 
    <groupId>com.fasterxml.jackson.datatype</groupId> 
    <artifactId>jackson-datatype-joda</artifactId> 
    <version>2.4.0</version> 
</dependency> 

뉴저지 2.12

희망이 어떻게 든 도움이되었다.

@POST 
@Path("/{memberId}") 
@Produces(MediaType.APPLICATION_JSON) 
@Consumes(MediaType.APPLICATION_JSON) 
public ResultBean recordDate(@PathParam("memberId") Long memberId, DateTime dateTime) { 
    // TODO stuff happens 
    return new ResultBean(memberId, dateTime); 
} 

당신은 할 수 : 대신

+0

Jackson과 MOXy는 2 가지 JSON 공급자입니다. –

+0

당신의 요점이 보이지 않습니다. 문제는 패스하는 법이었습니다. 어떻게 폭시와 합격 할 것인가가 아닙니다. – zyexal

+0

귀하의 솔루션은 작동하지만, OP가 "My Jersey는 MOXy를 사용합니다"라고 쓰는 동안 Jackson이 필요합니다. –

1

DateTimeWrapper의 모습
@POST 
@Path("/{memberId}") 
@Produces(MediaType.APPLICATION_JSON) 
@Consumes(MediaType.APPLICATION_JSON) 
public ResultBean recordDate(@PathParam("memberId") Long memberId, DateTimeWrapper dateTimeWrapper) { 
    // TODO stuff happens 
    return new ResultBean(memberId, dateTime); 
} 

. DateTime 개체가 이제 최상위 개체가 아닌 속성이므로 XmlAdapter이 적용됩니다.

@XmlAccessorType(XmlAccessType.FIELD) 
public class DateTimeWrapper { 

    @XmlValue 
    @XmlJavaTypeAdapter(YourDateTimeAdapter.class) 
    private DateTime value; 

} 
+0

고마워요. @Blaise, 이것은 확실히 작동 할 것입니다. 나는 래퍼를 추가하지 않고 그것을하는 방법을 찾고 있었어. 주어진 설정으로 할 수있는 방법을 찾을 수 없다는 것을 감안할 때, 아마도 이것이 최선의 방법 일 것입니다. –

+0

@ MarkS - 자신 만의'MessageBodyReader' /'MessageBodyWriter'를 작성할 수는 있지만 JSON을 직접 처리해야합니다. –

관련 문제