在Dropwizard中启用对资源的验证

时间:2014-10-01 09:07:48

标签: java validation rest dropwizard

我使用Dropwizard 0.7运行Java 8

我无法通过Dropwizard中的资源进行验证

我有以下bean

@Data //lombok anntation
@JsonRootName(value="CreateNewGame")
@XmlRootElement
public class CreateNewGameDTO {
    @NotEmpty
    public String name;

    @NotNull
    private GameType type;
    @NotBlank
    private String username;

    @NotNull
    @Min(1)
    private Integer numOfPlayers;
}

在我的Resource类中,我有以下方法

@POST
@Timed
public Response createGame(@Valid CreateNewGameDTO dto) { ... }

My JUnit test

@ClassRule
public static final DropwizardAppRule<CivBoardGameRandomizerConfiguration> RULE =
        new DropwizardAppRule<CivBoardGameRandomizerConfiguration>(CivBoardgameRandomizerApplication.class, "src/main/resources/config.yml");

@Test
public void createGameShouldFailBecauseOfMissingUsername() throws Exception {
    List<NewCookie> cookies = performLogin();
    assertThat(cookies.size()).isEqualTo(2);

    Client client = Client.create();

    CreateNewGameDTO dto = new CreateNewGameDTO();
    dto.setNumOfPlayers(4);
    dto.setUsername(null); //Username NULL, so it should throw exception
    dto.setName("PBF WaW");
    dto.setType(GameType.WAW);

    ObjectMapper mapper = new ObjectMapper();
    String dtoAsJSon = mapper.writeValueAsString(dto);

    URI uri = UriBuilder.fromPath(String.format(BASE_URL + "/game", RULE.getLocalPort())).build();
    ClientResponse response = client.resource(uri)
            .type(MediaType.APPLICATION_JSON)
            .cookie(cookies.get(0))
            .cookie(cookies.get(1))
            .entity(dtoAsJSon)
            .post(ClientResponse.class);

    assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED_201);
    URI location = response.getLocation();
    assertTrue(location.getPath().matches(".*civilization/game/.*"));
}

当我创建一个单元测试来调用此资源时,我得到以下异常

ERROR [2014-10-01 11:03:39,515] com.sun.jersey.spi.container.ContainerResponse: A message body writer for Java class io.dropwizard.jersey.validation.ValidationErrorMessage, and Java type class io.dropwizard.jersey.validation.ValidationErrorMessage, and MIME media type application/xml was not found.
The registered message body writers compatible with the MIME media type are:
*/* ->
  com.sun.jersey.core.impl.provider.entity.FormProvider
  com.sun.jersey.core.impl.provider.entity.StringProvider
  com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
  com.sun.jersey.core.impl.provider.entity.FileProvider
  com.sun.jersey.core.impl.provider.entity.InputStreamProvider
  com.sun.jersey.core.impl.provider.entity.DataSourceProvider
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.ReaderProvider
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.StreamingOutputProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
  com.sun.jersey.server.impl.template.ViewableMessageBodyWriter
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
  com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider
application/xml ->
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$App
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$App
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$App

我还没有做任何事情来注册&#34;验证。我以为dropwizard会自动执行此操作。我还没有在文档中找到任何内容。 我使用0.7版本的Dropwizard

2 个答案:

答案 0 :(得分:0)

您可以尝试在资源中添加@Produces注释,例如@Produces(MediaType.APPLICATION_JSON),在特定方法之上或整个类上,看看是否有效?我想我只是在相同的事情上发生了变化。如果是这种情况,则意味着Dropwizard无法确定MessageBodyWriter用于该tupe的响应(我认为)

答案 1 :(得分:0)

问题是,抛出异常并且没有exceptionMapper可以将其映射到有效输出。你可以试试这个:

@Provider
@Produces(MediaType.TEXT_PLAIN)
public class ValidationErrorMessageBodyWriter implements MessageBodyWriter<ValidationErrorMessage> {

    private static final Logger LOG = LoggerFactory.getLogger(ValidationErrorMessageBodyWriter.class);

    @Override
    public boolean isWriteable(
        Class<?> type,
        Type genericType,
        Annotation[] annotations,
        MediaType mediaType)
    {
        return ValidationErrorMessage.class.isAssignableFrom(type);
    }

    @Override
    public long getSize(
        ValidationErrorMessage t,
        Class<?> type,
        Type genericType,
        Annotation[] annotations,
        MediaType mediaType)
    {
        return -1;
    }

    @Override
    public void writeTo(
        ValidationErrorMessage t,
        Class<?> type,
        Type genericType,
        Annotation[] annotations,
        MediaType mediaType,
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException, WebApplicationException
    {
        Joiner joiner = Joiner.on("; ").skipNulls();
        String message = joiner.join(t.getErrors().iterator());
        entityStream.write(message.getBytes(Charsets.UTF_8));
        LOG.info(message);
    }

}

现在添加app app(config,enviroment)方法:

    // Serializer
    environment.jersey().register(new ValidationErrorMessageBodyWriter());      

也许您想修改BodyWriter以生成其他输出,如xml或sth。其他!希望这能解决您的问题: - )


编辑 :评论中的问题

在您的一个资源中添加:

@GET
@Path("getMBW")
public Response getInTestResource(@Context  MessageBodyWorkers workers)
{
    Map<MediaType, List<MessageBodyWriter>> writers = workers.getWriters(MediaType.WILDCARD_TYPE);

    for (Entry<MediaType, List<MessageBodyWriter>> entry : writers.entrySet()) {
        for (MessageBodyWriter  writer : entry.getValue()) {
            System.out.println(String.format("For mediaType '%s' there is a class called %s", entry.getKey(),writer.getClass().getName()));
        }
    }       
    return Response.status(Status.OK).type(MediaType.TEXT_PLAIN).entity("get is ok").build();
}

然后我明白了:

For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.FormProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.StringProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.FileProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.InputStreamProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.DataSourceProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.ReaderProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.DocumentProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.StreamingOutputProvider
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
For mediaType '*/*' there is a class called com.sun.jersey.server.impl.template.ViewableMessageBodyWriter
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
For mediaType '*/*' there is a class called com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
For mediaType '*/*' there is a class called com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider