使用 jax-rs,我不确定如何手动将 JSON 解组到我的自定义 Java 对象中。
从我的浏览器中,我发送了一个带有以下 JSON 的简单 put 请求:
{"myDate":{"dayOfMonth":23, "monthOfYear":7, "year":2011}}
在服务器上,我有一个 BlahResource,它使用这个 JSON 并打印出 Java 对象属性:
@Component
@Scope("request")
@Path("/blah")
@Consumes("application/json")
@Produces("application/json")
public class BlahResource {
@PUT
public String putBlah(Blah blah) {
System.out.println("Value: " + blah.getMyDate().getMonthOfYear() + "/" + blah.getMyDate().getDayOfMonth() + "/" + blah.getMyDate().getYear());
return "{}";
}
}
这是 Blah 的源代码:
public class Blah {
private LocalDate myDate;
public Blah()
{
}
public void setMyDate(LocalDate myDate)
{
this.myDate = myDate;
}
public LocalDate getMyDate()
{
return myDate;
}
}
问题是 Blah.myDate 是一个 Joda-time LocalDate 类,它没有 dayOfMonth、monthOfYear 和 year 的设置器。因此,例如,当我运行它时,会引发以下异常:
Jul 10, 2011 8:40:33 AM
com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The exception contained within MappableContainerException could not
be mapped to a response, re-throwing to the HTTP container
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "dayOfMonth"
这对我来说很有意义。问题是我不知道如何编写某种适配器,以便每当遇到类型 LocalDate 时,我的适配器类用于将 JSON 转换为 LocalDate。
理想情况下,我想做这样的事情:
public class LocalDateAdapter {
public LocalDate convert(String json)
{
int dayOfMonth = (Integer)SomeJsonUtility.extract("dayOfMonth");
int year = (Integer)SomeJsonUtility.extract("year");
int monthOfYear = (Integer)SomeJsonUtility.extract("monthOfYear");
return new LocalDate(year, monthOfYear, dayOfMonth);
}
}
更新
我现在尝试了两种方法,似乎都没有奏效。
1)使用对象映射器
看来我需要做的就是获取 ObjectMapper 的句柄并添加一个反序列化器。所以我创建了这个提供者。令我惊讶的是,我将我的 dserializer 命名为:LocalDateDeserializer,当我有 eclipse 自动修复导入时,我震惊地看到 Jackson 已经为 Joda 提供了一个扩展。当我启动服务器时,它会找到提供程序,但否则似乎从未调用过此代码。
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ext.JodaDeserializers.LocalDateDeserializer;
import org.codehaus.jackson.map.module.SimpleModule;
import org.joda.time.LocalDate;
import org.springframework.stereotype.Component;
@Component
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
@Override
public ObjectMapper getContext(Class<?> type) {
ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null))
.addDeserializer(LocalDate.class, new LocalDateDeserializer());
mapper.registerModule(testModule);
return mapper;
}
}
2)我尝试的第二种方法是直接在字段上指定@JsonDeserialize 注解。
@JsonDeserialize(using = CustomDateDeserializer.class)
private LocalDate myDate;
这似乎也没有被调用。
public class CustomDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException
{
return new LocalDate(2008, 2, 5);
}
}
我不知道该怎么办。这似乎是一个非常基本的问题。
更新 2
我正在考虑放弃使用反序列化的杰克逊(即使它与泽西岛配合得很好)。
我已经在使用 flexjson 进行序列化,而且似乎 flexjson 对反序列化同样简单。所有这些其他库都有一些抽象和不必要的复杂性。
在 Flexjson 中,我只需要实现 ObjectFactory:
class LocalDateTransformer implements ObjectFactory {
@Override
public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass)
{
HashMap map = (HashMap)value;
int year = (Integer)map.get("year");
int monthOfYear = (Integer)map.get("monthOfYear");
int dayOfMonth = (Integer)map.get("dayOfMonth");
return new LocalDate(year, monthOfYear, dayOfMonth);
}
}
它看起来很像我最初发布的“适配器”类!我的资源方法现在变成了:
@PUT
public String putBlah(String blahStr) {
Blah blah = new JSONDeserializer<Blah>().use(LocalDate.class, new LocalDateTransformer()).deserialize(blahStr, Blah.class);
}