【问题标题】:Jackson JsonDeserialize not being called for @QueryParam没有为@QueryParam 调用 Jackson JsonDeserialize
【发布时间】:2015-10-15 06:05:12
【问题描述】:

我已经映射了一个自定义反序列化器,以将 dd/MM/yyyy 模式上的字符串转换为 LocalDate,这样我就可以使用更具可读性的签名来调用我的服务..

这是我的 dto 类,用作 Jersey @BeanParam 在层之间传输数据:

public class ProdutoFilterDto implements FilterDto {

private static final long serialVersionUID = -4998167328470565406L;

@QueryParam("dataInicial")
@JsonDeserialize(using = CustomLocalDateDeserializer.class)
private LocalDate dataInicial;

@QueryParam("dataInicial")
@JsonDeserialize(using = CustomLocalDateDeserializer.class)
private LocalDate dataFinal;

public LocalDate getDataInicial() {
    return dataInicial;
}

public void setDataInicial(LocalDate dataInicial) {
    this.dataInicial = dataInicial;
}

public LocalDate getDataFinal() {
    return dataFinal;
}

public void setDataFinal(LocalDate dataFinal) {
    this.dataFinal = dataFinal;
}

}

这是我的自定义反序列化器:

public class CustomLocalDateDeserializer extends JsonDeserializer<LocalDate> {

@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    final String data = p.getValueAsString();
    return (LocalDate) formatter.parse(data);
}

}

它被用于这项运动衫服务:

@Path("produto")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProdutoService {

...

@GET
@Path("query")
@Override
public Response query(
        @QueryParam("offset") @DefaultValue(value = "0") Integer offSet, 
        @QueryParam("limit") @DefaultValue(value = "10") Integer limit, 
        @BeanParam ProdutoFilterDto filter) { ... }

...

}

我是这样打电话的:

${host goes here}/produto/query?dataInicial=11/09/1992

问题是反序列化器方法从未被调用,并且bean参数变量保持为空..

【问题讨论】:

  • 你配置你的 web.xml 了吗?意思是你定义了 servlet Jersey 并映射了它?

标签: java json jackson jax-rs jersey-2.0


【解决方案1】:

MessageBodyReaders 不用于@QueryParam。您似乎期望 Jackson MessageBodyReader 处理这种反序列化,但它不是那样工作的。

相反,您需要使用ParamConverter,这需要通过ParamConverterProvider 注册。例如:

@Provider
public class LocalDateParamConverterProvider implements ParamConverterProvider {

    final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");

    @Override
    public <T> ParamConverter<T> getConverter(
            Class<T> rawType, Type genericType, Annotation[] antns) {

        if (LocalDate.class == rawType) {
            return new ParamConverter<T>() {
                @Override
                public T fromString(String string) {
                    try {
                        LocalDate localDate = LocalDate.parse(string, formatter);
                        return rawType.cast(localDate);
                    } catch (Exception ex) {
                        throw new BadRequestException(ex);
                    }
                }

                @Override
                public String toString(T t) {
                    LocalDate localDate = (LocalDate) t;
                    return formatter.format(localDate);
                }
            };
        }

        return null;
    }
}

现在LocalDate 将与@QueryParam 和其他@XxxParams 一起工作。

注意事项:

  • 如果您的目标是将您的 @XxxParams 和 JSON 正文都解析为一个 bean,这将不起作用。我不确定这会如何工作,但我确信它会涉及大量黑客攻击,因此我不推荐它。

  • 您对(LocalDate) 的转换将不起作用。这是对java.time.format.Parsed 的非法转换。请参阅代码示例中的正确方法。

  • 与以上几点有关。使用您的解析代码,我花了一个小时试图弄清楚为什么我得到 404。对于 404,我想看的最后一个地方是 ParamConverter。但似乎ParamConverter 中抛出的任何未捕获的异常都会导致 404。这没什么意义吧?头晕目眩把我带到this,又把我带到this,这似乎是一个糟糕的规范

    "如果字段或属性被注释 @MatrixParam、@QueryParam 或 @PathParam 然后实现必须生成 NotFoundException (404 状态) 包装了抛出的异常并且没有实体 "

    故事的寓意:确保在ParamConverter! 中捕获任何可能的异常!

另请参阅:

【讨论】:

  • 关于如何使其适用于 pathparam 的任何建议?
  • 我有一个带有多个查询和路径参数的 beanparam。仅对一个查询参数调用 getConverter 方法。有什么建议吗?
  • 它应该仍然可以工作。如果您想发布另一个带有完整示例的问题,我有机会可以看看它
猜你喜欢
  • 2018-02-22
  • 2015-03-22
  • 1970-01-01
  • 2018-11-21
  • 2023-03-13
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多