我想将 org.joda.time.DateTime 作为 json POST 的消息正文传递到 Jersey 端点。我的 Jersey 使用 MOXy。我创建了一个自定义 XmlAdapter 来执行此操作,但我不清楚如何连接此适配器。我找到的自定义适配器的示例在要发布的对象上使用注释,但我无法做到这一点(我无法在 DateTime 类上放置注释,因为我无法操作其源代码)。
我正在使用 Jersey-test 框架来测试这一点。
我的泽西端点:
@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);
}
我的 Jersey 测试:
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 错误。
最佳答案
首先要做的事情是:您需要一个用于 joda DateTime 的 MessageBodyReader/Writer
。
如果不进行一些调整,JSON 序列化日期时间的 POST 似乎将无法工作。 Gson 序列化的 DateTime 将如下所示:
{ "iMillis": 1414507195233,
"iChronology": {
"iBase": {
"iBase": {
...
},
"iParam": {
...
}}}}
如果您尝试使用 Gson 再次反序列化,Gson 将失败,因为 org.joda.time.Chronology
-> iChronology
没有默认值 -non-arg构造函数,Gson需要反序列化对象。 Afaig,在使用任何标准反序列化器反序列化 DateTime 时,您最终都会遇到此类问题。
所以我最终基于 FasterXML/jackson-datatype-joda 创建了 MessageBodyReader/Writer
读者:
// ...
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);
}
}
}
作者:
// ...
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);
}
}
}
两者都在 ResourceConfig 中注册。
作者将回复 1414507195233(是的,不是 JSON),如果您将其发布回您的资源,您将获得一个有效的日期时间。
如果您获得像上面的示例一样的 JSON,您现在可以升级 Reader 以解析 iMillis 的 JSON 并使用 Long 值。对于 TimeZone,您可以执行相同的操作并使用 dateTime.withZone(...)
来设置值。
我使用过的 Maven 依赖项:
<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>
Jersey 2.12
希望这对您有所帮助。
关于json - 如何将 Joda DateTime 对象作为 HTTP POST 的消息正文传递到 Jersey REST 端点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26556743/