如何使用 vertx 和 quarkus 发布静态集合

How to publish static collection with vertx and quarkus

我正在使用 Quarkus 构建一个应用程序,它是 vert.x 扩展。现在我想构建一个 REST 端点,它应该流式传输所有保存的地址。为了在没有反应性数据源的情况下测试这个,我不想创建一个带有示例地址的 ArrayList 并流式传输它们,这样我就可以检查我的测试是否有效。但是我找不到如何流式传输集合。

我的实际代码:

    import io.vertx.reactivex.core.Vertx;
    import org.reactivestreams.Publisher;

    import javax.inject.Inject;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import java.util.ArrayList;
    import java.util.Collection;

    @Path("/addresses")
    public class AddressResource {
      private Collection<Address> adresses;

      @Inject private Vertx vertx;

      public AddressResource() {
        super();
        adresses = new ArrayList<>();
      }

      @GET
      @Produces(MediaType.SERVER_SENT_EVENTS)
      public Publisher<Address> get() {
        Address address = new Address();
        address.setStreet("590 Holly Street");
        address.setCity("Townsend");
        address.setState("Ohio");
        address.setZip(6794);
        adresses.add(address);
        adresses.add(address);
        adresses.add(address);
        adresses.add(address);
        adresses.add(address);
        adresses.add(address);

        // What to do here?
        return null;
      }
    }

这是我的测试:

    import io.quarkus.test.junit.QuarkusTest;
    import org.hamcrest.Matchers;
    import org.junit.jupiter.api.Test;

    import javax.json.bind.JsonbBuilder;
    import java.util.ArrayList;
    import java.util.List;

    import static io.restassured.RestAssured.given;

    @QuarkusTest
    public class DBServiceTest {

      @Test
      void testGetAddresses() throws InterruptedException {
        given()
            .when()
            .get("/addresses")
            .then()
            .statusCode(200)
            .body(Matchers.containsInAnyOrder(readTestAdresses().toArray()));
      }

      private List<Address> readTestAdresses() {
        return JsonbBuilder.create()
            .fromJson(
                this.getClass().getResourceAsStream("test-addresses.json"),
                new ArrayList<Address>() {}.getClass().getGenericSuperclass());
      }
    }

编辑 1: 我尝试了以下方法:


    @GET
      @Produces(MediaType.SERVER_SENT_EVENTS)
      public Publisher<String> get() {
        Address address = new Address();
        address.setStreet("590 Holly Street");
        address.setCity("Townsend");
        address.setState("Ohio");
        address.setZip(6794);
        adresses.add(address);
        return Flowable.just("Test 1","Test 2","Test 3");
      }

这行得通。所以问题一定与地址对象有关。

您可以使用

  @GET
  @Produces(MediaType.SERVER_SENT_EVENTS)
  public Publisher<String> get() {
    Address address = new Address();
    address.setStreet("590 Holly Street");
    address.setCity("Townsend");
    address.setState("Ohio");
    address.setZip(6794);
    return Flowable.just(address, address, address,....).map(a -> yourToString(a));
  }

其中 yourToString 是一种将创建正确字符串表示的方法(可能是 json)。

我可以修复它,我错过了一个依赖项:

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>

并且必须手动将我的对象转换为 json 等等,将 return 类型更改为 Publisher<String>:

    import io.reactivex.Flowable;
    import io.vertx.core.json.Json;
    import org.reactivestreams.Publisher;

    import javax.ws.rs.Consumes;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import java.util.ArrayList;
    import java.util.Collection;

    @Path("/addresses")
    @Consumes(MediaType.APPLICATION_JSON)
    public class AddressResource {
      private Collection<Address> addresses;

      public AddressResource() {
        super();
        addresses = new ArrayList<>();
      }

      @GET
      @Produces(MediaType.SERVER_SENT_EVENTS)
      public Publisher<String> get() {
        Address address = new Address();
        address.setStreet("590 Holly Street");
        address.setCity("Townsend");
        address.setState("Ohio");
        address.setZip(6794);
        addresses.add(address);
        return Flowable.fromIterable(addresses).map(Json::encode);
      }
    }

我的测试也是错误的,现在是这样的:

    import io.quarkus.test.common.http.TestHTTPResource;
    import io.quarkus.test.junit.QuarkusTest;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;

    import javax.json.bind.JsonbBuilder;
    import javax.ws.rs.client.Client;
    import javax.ws.rs.client.ClientBuilder;
    import javax.ws.rs.client.WebTarget;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.sse.SseEventSource;
    import java.net.URL;
    import java.util.*;
    import java.util.concurrent.CompletableFuture;

    import static org.assertj.core.api.Assertions.assertThat;

    @QuarkusTest
    public class DBServiceTest {

      @TestHTTPResource("/addresses")
      private URL enpointUrl;

      @Test
      @DisplayName("Get all addresses")
      void testGetAddresses() {
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(String.valueOf(enpointUrl));
        try (SseEventSource source = SseEventSource.target(target).build()) {
          CompletableFuture<Collection<Address>> futureAddresses = new CompletableFuture<>();
          Set<Address> foundAddresses = new HashSet<>();
          source.register(
              event -> {
                if (!foundAddresses.add(
                    event.readData(Address.class, MediaType.APPLICATION_JSON_TYPE))) {
                  futureAddresses.complete(foundAddresses);
                }
              },
              Assertions::fail);
          source.open();
          Collection<Address> addresses = futureAddresses.join();
          assertThat(addresses).containsExactlyInAnyOrderElementsOf(readTestAdresses());
        }
      }

      private List<Address> readTestAdresses() {
        return JsonbBuilder.create()
            .fromJson(
                this.getClass().getResourceAsStream("test-addresses.json"),
                new ArrayList<Address>() {}.getClass().getGenericSuperclass());
      }
    }