Spring没有检测到Json Deserializer

时间:2014-04-26 14:22:14

标签: json spring deserialization json-deserialization fasterxml

我有一个Spring Rest Controller和一个“命令”/ DTO对象,用于控制器上的POST方法。我还为其中一个字段“due”编写了一个序列化器/反序列化器 - 这是一个Calendar对象。

由于在pom.xml中定义了Jackson2依赖项,我希望Spring能够检测到我的反序列化器并使用它将String输入转换为java.util.Calendar。但是,我得到了“找不到匹配的编辑器或转换策略”的例外情况。我的序列化器正在工作......只有解串器不起作用!

Rest Controller(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(代码未在此处显示)时,正确调用了序列化程序,并且我看到了“Task”对象的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中的字符串,并使用反序列化器将其转换为java.util.Calendar。我错过了什么?

2 个答案:

答案 0 :(得分:0)

想出这个。

当使用Curl进行HTTP POST时,如描述中所示(带有-d标志),POST带有内容类型&#34; application / x-www-form-urlencoded&#34; (后见之明显而易见,因为它被视为网络表单数据)。这会触发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;
    }

现在反序列化器被触发,输入到期日期正确地从String转换为Calendar对象。

答案 1 :(得分: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)