0

我有一个 Spring Rest 控制器和一个用于控制器上 POST 方法的“命令”/DTO 对象。我还为“到期”字段之一编写了一个序列化器/反序列化器——它是一个日历对象。

由于 Jackson2 依赖项是在 pom.xml 中定义的,因此我希望 Spring 能够检测到我的反序列化器并使用它将字符串输入转换为 java.util.Calendar。但是,我收到“未找到匹配的编辑器或转换策略”异常。我的序列化器正在工作……只有反序列化器不起作用!

休息控制器 (TaskController.java)

@Controller
public class TasksController {

    ...

    @RequestMapping(value = "/tasks", method = RequestMethod.POST)
    public @ResponseBody Task createTask(@Valid TasksCommand tasksCommand){

        Task task = new Task();
        task.setName(tasksCommand.getName());
        task.setDue(tasksCommand.getDue());
        task.setCategory(tasksCommand.getCategory());

        return task;
    }
}

命令 /dto 对象:

public class TasksCommand {

    @NotBlank
    @NotNull
    private String name;

    @JsonDeserialize(using = CalendarDeserializer.class)
    @JsonSerialize(using = CalendarSerializer.class)
    private Calendar due;

    private String category;

    ... getters & setters ...
}

日历的序列化器 - 用于我的自定义日期格式

public class CalendarSerializer extends JsonSerializer<Calendar>{

        @Override
        public void serialize(Calendar calendar, JsonGenerator jgen, SerializerProvider provider)
                throws IOException, JsonProcessingException {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss Z"); // Z - RFC 822 time zone

            jgen.writeString(simpleDateFormat.format(calendar.getTime()));

        }

}

日历的反序列化器

public class CalendarDeserializer extends JsonDeserializer<Calendar> {

    private static Logger logger = Logger.getLogger(CalendarDeserializer.class);

    @Override
    public Calendar deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException, JsonProcessingException {

        String dateStr = jsonParser.getText();
        logger.info("deserializing date:" + dateStr);

        return Calendar.getInstance();

    }
}

我在 Maven 中指定了 Jackson2 依赖项。执行 GET(此处未显示代码)时,序列化程序被正确调用,并且我看到“任务”对象的 JSON 输出。

但是,当我如下进行 HTTP POST 时

curl -X POST -d name=task1 -d category=weekly -d due=01/01/2013 http://localhost:8080/tasks

解串器从未被检测到,我得到一个异常

Failed to convert property value of type java.lang.String to required type java.util.Calendar for property due; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.util.Calendar] for property due: no matching editors or conversion strategy found

由于检测到序列化程序,我不明白为什么没有检测到并正确调用反序列化程序。根据我的阅读,Spring 将检测到在类路径上有 Jackson2 库,它会自动将 MappingJackson2HttpMessageConverter 添加到消息转换器列表中。所以这段代码应该检测 HTTP POST 中的字符串,并使用 Deserializer 将其转换为 java.util.Calendar。我错过了什么?

4

2 回答 2

2

想出了这个。

当使用 Curl 进行 HTTP POST 时,如描述所示(使用 -d 标志),POST 带有内容类型“application/x-www-form-urlencoded”(事后看来很明显,因为它被视为 Web 表单数据)。这会触发 Spring FormHttpMessageConverter 消息转换器,并且永远不会触发 MappingJackson2HttpMessageConverter 转换器。

但是,序列化器和反序列化器使用 Jackson 注释进行注释,只有 MappingJackson2HttpMessageConverter 知道如何处理。这就是导致问题中描述的异常的原因。

解决方法是在 curl 命令中传入 JSON 数据:

curl -X POST -H "Content-Type: application/json" -d '{"name":"test1","due":"1/1/2013","category":"weekly"}' http://localhost:8080/tasks

此外,由于 JSON 输入来自 HTTP POST 调用的主体,我们需要在 Controller 方法签名中使用 @RequestBody 注释。

@RequestMapping(value = "/tasks", method = RequestMethod.POST)
    public @ResponseBody Task createTask(@RequestBody @Valid TasksCommand tasksCommand){

        Task task = new Task();
        task.setName(tasksCommand.getName());
        task.setDue(tasksCommand.getDue());
        task.setCategory(tasksCommand.getCategory());

        return task;
    }

现在反序列化器被触发并且输入的截止日期正确地从字符串转换为日历对象。

于 2014-04-28T22:46:57.467 回答
0

尝试自定义类

public class DateDeserializer implements JsonDeserializer<Date> {

    @Override
    public Date deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
        String date = element.getAsString();
        return TimeService.parseDate(date,"yyyy-MM-dd'T'HH:mm:ss");

    }
}

然后将其添加到您的 gson 构建器

GsonBuilder gsonBuilder = new GsonBuilder();
            gsonBuilder.registerTypeAdapter(Date.class, new DateDeserializer());
gsonBuilder.create().fromJson(eventsJson, yourTargetClass.class)
于 2018-04-24T09:47:58.660 回答