我已经映射了一个自定义解串器,以将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 param变量保持为空。

最佳答案

MessageBodyReader不用于@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和其他@XxxParam一起使用。

注意事项:
  • 如果您的目标是将@XxxParam和JSON正文都解析为bean,则将无法使用。我不确定这将如何工作,但是我确定它会涉及很多黑客行为,因此我不建议这样做。
  • 您强制转换为(LocalDate)无效。这是对java.time.format.Parsed的非法转换。在代码示例中查看正确的方法。
  • 与以上几点有关。我花了好一个小时拉着头发,试图用您的解析代码弄清楚为什么我得到404。使用404,我想看的最后一个地方是ParamConverter。但是,似乎在ParamConverter中引发的任何未捕获的异常都将导致404。这不是很有意义吗?头部重击导致我进入this,这导致我进入this,这似乎是一个糟糕的规范

    “如果字段或属性用
    @ MatrixParam,@ QueryParam或@PathParam,则实现必须生成一个实例
    NotFoundException(状态为404),用于包装引发的异常并且不包含任何实体


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

  • 另请参见:
  • Good article on ParamConverters
  • 08-04 22:55