You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2020/12/30 02:06:22 UTC
[cxf] branch master updated: CXF-8343: Add JSON-B support
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/master by this push:
new 2696ea2 CXF-8343: Add JSON-B support
2696ea2 is described below
commit 2696ea28b67f21b310e400b990da50016b62bd90
Author: reta <dr...@gmail.com>
AuthorDate: Tue Dec 29 21:05:59 2020 -0500
CXF-8343: Add JSON-B support
---
rt/rs/extensions/providers/pom.xml | 12 +-
.../jaxrs/provider/jsrjsonb/JsrJsonbProvider.java | 108 +++++++++
.../provider/jsrjsonb/JsrJsonbProviderTest.java | 133 +++++++++++
systests/jaxrs/pom.xml | 17 +-
.../apache/cxf/systest/jaxrs/provider/Book.java | 4 +
.../cxf/systest/jaxrs/provider/BookJsonStore2.java | 77 ++++++
.../jaxrs/provider/JsrJsonbProviderTest.java | 259 +++++++++++++++++++++
7 files changed, 605 insertions(+), 5 deletions(-)
diff --git a/rt/rs/extensions/providers/pom.xml b/rt/rs/extensions/providers/pom.xml
index 3aa2337..ab257ff 100644
--- a/rt/rs/extensions/providers/pom.xml
+++ b/rt/rs/extensions/providers/pom.xml
@@ -119,7 +119,12 @@
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<optional>true</optional>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.json.bind</groupId>
+ <artifactId>jakarta.json.bind-api</artifactId>
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-bindings-soap</artifactId>
@@ -147,6 +152,11 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-jsonb</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/jsrjsonb/JsrJsonbProvider.java b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/jsrjsonb/JsrJsonbProvider.java
new file mode 100644
index 0000000..621d667
--- /dev/null
+++ b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/jsrjsonb/JsrJsonbProvider.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.jaxrs.provider.jsrjsonb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.json.JsonException;
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.cxf.jaxrs.utils.ExceptionUtils;
+
+/**
+ * 11.2.7 Java API for JSON Binding (JSR-370)
+ *
+ * In a product that supports the Java API for JSON Binding (JSON-B) [19], implementations MUST support
+ * entity providers for all Java types supported by JSON-B in combination with the following media
+ * types: application/json, text/json as well as any other media types matching "*"/json or "*"/"*"+json".
+ *
+ * Note that if JSON-B and JSON-P are both supported in the same environment, entity providers for
+ * JSON-B take precedence over those for JSON-P for all types except JsonValue and its sub-types.
+*/
+@Produces({"application/json", "text/json", "application/*+json" })
+@Consumes({"application/json", "text/json", "application/*+json" })
+@Provider
+public class JsrJsonbProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object> {
+ private final Jsonb jsonb;
+
+ public JsrJsonbProvider() {
+ this(JsonbBuilder.create());
+ }
+
+ public JsrJsonbProvider(Jsonb jsonb) {
+ this.jsonb = jsonb;
+ }
+
+ @Override
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return isSupportedMediaType(mediaType);
+ }
+
+ @Override
+ public void writeTo(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+ throws IOException, WebApplicationException {
+ jsonb.toJson(t, type, entityStream);
+ }
+
+ @Override
+ public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+ return isSupportedMediaType(mediaType);
+ }
+
+ @Override
+ public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
+ MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+ throws IOException, WebApplicationException {
+ try {
+ if (genericType == null) {
+ return jsonb.fromJson(entityStream, type);
+ } else {
+ return jsonb.fromJson(entityStream, genericType);
+ }
+ } catch (JsonException ex) {
+ throw ExceptionUtils.toBadRequestException(ex, null);
+ }
+ }
+
+ protected boolean isSupportedMediaType(MediaType mediaType) {
+ if (mediaType != null) {
+ final String subtype = mediaType.getSubtype();
+ return "json".equalsIgnoreCase(subtype) || subtype.endsWith("+json");
+ } else {
+ // Return 'false' if no media type has been specified
+ return false;
+ }
+ }
+
+}
diff --git a/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/jsrjsonb/JsrJsonbProviderTest.java b/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/jsrjsonb/JsrJsonbProviderTest.java
new file mode 100644
index 0000000..8515bc5
--- /dev/null
+++ b/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/jsrjsonb/JsrJsonbProviderTest.java
@@ -0,0 +1,133 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.jaxrs.provider.jsrjsonb;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.jaxrs.resources.Book;
+import org.apache.cxf.jaxrs.resources.CollectionsResource;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertThrows;
+
+public class JsrJsonbProviderTest {
+ private JsrJsonbProvider provider;
+
+ @Before
+ public void setUp() {
+ provider = new JsrJsonbProvider();
+ }
+
+ @Test
+ public void testReadMalformedJson() throws Exception {
+ final byte[] bytes = "junk".getBytes();
+ final WebApplicationException ex = assertThrows(WebApplicationException.class, () -> read(Book.class, bytes));
+ assertThat(ex.getResponse().getStatus(), equalTo(Response.Status.BAD_REQUEST.getStatusCode()));
+ }
+
+ @Test
+ public void testReadListOfBooks() throws Exception {
+ final String input = "["
+ + "{"
+ + " \"name\":\"CXF 1\""
+ + "},"
+ + "{"
+ + " \"name\":\"CXF 2\""
+ + "}"
+ + "]";
+
+ final Method m = CollectionsResource.class.getMethod("getBooks", new Class[]{});
+ final List<Book> books = read(m.getReturnType(), m.getGenericReturnType(), input.getBytes());
+
+ assertThat(books.size(), equalTo(2));
+ assertThat(books.get(0).getName(), equalTo("CXF 1"));
+ assertThat(books.get(1).getName(), equalTo("CXF 2"));
+ }
+
+ @Test
+ public void testWriteBook() throws Exception {
+ final Book book = new Book("CXF 1", 1);
+ final String payload = write(book, Book.class);
+
+ assertThat(payload, equalTo("{\"id\":1,\"name\":\"CXF 1\",\"state\":\"\"}"));
+ }
+
+ @Test
+ public void testReadBook() throws Exception {
+ String input = "{"
+ + "\"id\":1,"
+ + "\"name\":\"CXF 1\""
+ + "}";
+
+ final Book book = read(Book.class, input.getBytes());
+ assertThat(book.getId(), equalTo(1L));
+ assertThat(book.getName(), equalTo("CXF 1"));
+ }
+
+ @Test
+ public void testWriteListOfBooks() throws Exception {
+ final List<Book> books = new ArrayList<>();
+ books.add(new Book("CXF 1", 1));
+ books.add(new Book("CXF 2", 2));
+
+ final Method m = CollectionsResource.class.getMethod("setBooksArray", new Class[]{Book[].class});
+ final String payload = write(books, Book.class, m.getGenericParameterTypes()[0]);
+
+ assertThat(payload,
+ equalTo("[{\"id\":1,\"name\":\"CXF 1\",\"state\":\"\"},{\"id\":2,\"name\":\"CXF 2\",\"state\":\"\"}]"));
+ }
+
+ private <T> T read(Class<?> clazz, byte[] bytes) throws IOException {
+ return read(clazz, null, bytes);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T read(Class<?> clazz, Type genericType, byte[] bytes) throws IOException {
+ try (ByteArrayInputStream in = new ByteArrayInputStream(bytes)) {
+ return (T)provider.readFrom((Class<Object>)clazz, genericType, null, null, null, in);
+ }
+ }
+
+ private String write(Object value, Class<?> clazz) throws IOException {
+ return write(value, clazz, null);
+ }
+
+ @SuppressWarnings("unchecked")
+ private String write(Object value, Class<?> clazz, Type genericType) throws IOException {
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ provider.writeTo(value, (Class<Object>)clazz, genericType, null, null, null, out);
+ return out.toString(StandardCharsets.UTF_8.name());
+ }
+ }
+}
diff --git a/systests/jaxrs/pom.xml b/systests/jaxrs/pom.xml
index 9a834c9..4bafbe6 100644
--- a/systests/jaxrs/pom.xml
+++ b/systests/jaxrs/pom.xml
@@ -500,9 +500,9 @@
</exclusions>
</dependency>
<dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk15on</artifactId>
- <scope>test</scope>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
@@ -554,7 +554,16 @@
</exclusion>
</exclusions>
</dependency>
-
+ <dependency>
+ <groupId>jakarta.json.bind</groupId>
+ <artifactId>jakarta.json.bind-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-jsonb</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/Book.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/Book.java
index fcc074b..38ec370 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/Book.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/Book.java
@@ -59,4 +59,8 @@ public class Book {
public Collection<BookChapter> getChapters() {
return chapters.values();
}
+
+ public void setChapters(Collection<BookChapter> value) {
+ value.forEach(c -> chapters.put(c.getId(), c));
+ }
}
\ No newline at end of file
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/BookJsonStore2.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/BookJsonStore2.java
new file mode 100644
index 0000000..5579792
--- /dev/null
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/BookJsonStore2.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs.provider;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+@Path("/bookstore2/")
+public class BookJsonStore2 {
+ private Map< Long, Book > books = new HashMap<>();
+
+ @GET
+ @Path("/books/{bookId}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Book getBook(@PathParam("bookId") Long id) {
+ final Book book = books.get(id);
+
+ if (book == null) {
+ return null;
+ }
+
+ return book;
+ }
+
+ @GET
+ @Path("/books")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Collection<Book> getBooks() {
+ return books.values();
+ }
+
+ @POST
+ @Path("/books")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Book addBook(@Context final UriInfo uriInfo, Book book) {
+ books.put(book.getId(), book);
+ return book;
+ }
+
+ @DELETE
+ @Path("/books")
+ public Response deleteAll() {
+ books.clear();
+ return Response.ok().build();
+ }
+}
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/JsrJsonbProviderTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/JsrJsonbProviderTest.java
new file mode 100644
index 0000000..ee19064
--- /dev/null
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/provider/JsrJsonbProviderTest.java
@@ -0,0 +1,259 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs.provider;
+
+import java.util.Arrays;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.jaxrs.provider.jsrjsonb.JsrJsonbProvider;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class JsrJsonbProviderTest extends AbstractBusClientServerTestBase {
+ public static final String PORT = allocatePort(JsrJsonbProviderTest.class);
+
+ @Ignore
+ public static class Server extends AbstractBusTestServerBase {
+ protected void run() {
+ final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setResourceClasses(BookJsonStore.class, BookJsonStore2.class);
+ sf.setResourceProvider(BookJsonStore.class,
+ new SingletonResourceProvider(new BookJsonStore()));
+ sf.setResourceProvider(BookJsonStore2.class,
+ new SingletonResourceProvider(new BookJsonStore2()));
+ sf.setProvider(new JsrJsonbProvider());
+ sf.setAddress("http://localhost:" + PORT + "/");
+ sf.create();
+ }
+
+ public static void main(String[] args) {
+ try {
+ Server s = new Server();
+ s.start();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.exit(-1);
+ } finally {
+ System.out.println("done!");
+ }
+ }
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ AbstractResourceInfo.clearAllMaps();
+ //keep out of process due to stack traces testing failures
+ assertTrue("server did not launch correctly", launchServer(Server.class, true));
+ createStaticBus();
+ }
+
+ @Before
+ public void setUp() {
+ final Response r = createWebClient("/bookstore/books").delete();
+ assertEquals(Status.OK.getStatusCode(), r.getStatus());
+ }
+
+ @Test
+ public void testNoResultsAreReturned() throws Exception {
+ final Response r = createWebClient("/bookstore/books/155").get();
+ assertEquals(Status.NO_CONTENT.getStatusCode(), r.getStatus());
+ }
+
+ @Test
+ public void testPostSimpleJsonObject() {
+ final Response r = createWebClient("/bookstore/books")
+ .header("Content-Type", MediaType.APPLICATION_JSON)
+ .post(
+ Json
+ .createObjectBuilder()
+ .add("id", 1)
+ .add("name", "Book 1")
+ .build()
+ );
+ assertEquals(Status.CREATED.getStatusCode(), r.getStatus());
+ }
+
+ @Test
+ public void testPostComplexJsonObject() {
+ final Response r = createWebClient("/bookstore/books")
+ .header("Content-Type", MediaType.APPLICATION_JSON)
+ .post(
+ Json
+ .createObjectBuilder()
+ .add("id", 1)
+ .add("name", "Book 1")
+ .add("chapters",
+ Json.createArrayBuilder()
+ .add(
+ Json.createObjectBuilder()
+ .add("id", 1)
+ .add("title", "Chapter 1")
+ )
+ .add(
+ Json.createObjectBuilder()
+ .add("id", 2)
+ .add("title", "Chapter 2")
+ )
+ )
+ .build()
+ );
+ assertEquals(Status.CREATED.getStatusCode(), r.getStatus());
+ }
+
+ @Test
+ public void testPostAndGetSimpleJsonObject() {
+ testPostSimpleJsonObject();
+
+ final Response r = createWebClient("/bookstore/books/1").get();
+ assertEquals(Status.OK.getStatusCode(), r.getStatus());
+
+ JsonObject obj = r.readEntity(JsonObject.class);
+ assertThat(obj.getInt("id"), equalTo(1));
+ assertThat(obj.getString("name"), equalTo("Book 1"));
+ assertThat(obj.get("chapters"), nullValue());
+ }
+
+ @Test
+ public void testPostAndGetComplexJsonObject() {
+ testPostComplexJsonObject();
+
+ final Response r = createWebClient("/bookstore/books/1").get();
+ assertEquals(Status.OK.getStatusCode(), r.getStatus());
+
+ JsonObject obj = r.readEntity(JsonObject.class);
+ assertThat(obj.getInt("id"), equalTo(1));
+ assertThat(obj.getString("name"), equalTo("Book 1"));
+ assertThat(obj.get("chapters"), instanceOf(JsonArray.class));
+
+ final JsonArray chapters = (JsonArray)obj.get("chapters");
+ assertThat(chapters.size(), equalTo(2));
+ assertThat(((JsonObject)chapters.get(0)).getInt("id"), equalTo(1));
+ assertThat(((JsonObject)chapters.get(0)).getString("title"), equalTo("Chapter 1"));
+ assertThat(((JsonObject)chapters.get(1)).getInt("id"), equalTo(2));
+ assertThat(((JsonObject)chapters.get(1)).getString("title"), equalTo("Chapter 2"));
+ }
+
+ @Test
+ public void testPostAndGetJsonBooks() {
+ testPostSimpleJsonObject();
+
+ final Response r = createWebClient("/bookstore/books").get();
+ assertEquals(Status.OK.getStatusCode(), r.getStatus());
+
+ final JsonArray obj = r.readEntity(JsonArray.class);
+ assertThat(obj.size(), equalTo(1));
+ assertThat(obj.get(0), instanceOf(JsonObject.class));
+
+ assertThat(((JsonObject)obj.get(0)).getInt("id"), equalTo(1));
+ assertThat(((JsonObject)obj.get(0)).getString("name"), equalTo("Book 1"));
+ }
+
+ @Test
+ public void testPostBadJsonObject() {
+ final Response r = createWebClient("/bookstore/books")
+ .header("Content-Type", MediaType.APPLICATION_JSON)
+ .post("blabla");
+ assertEquals(Status.BAD_REQUEST.getStatusCode(), r.getStatus());
+ }
+
+ @Test
+ public void testPostBook() {
+ final Book response = createWebClient("/bookstore2/books")
+ .header("Content-Type", MediaType.APPLICATION_JSON)
+ .post(new Book("Book 1", 1L))
+ .readEntity(Book.class);
+
+ assertThat(response.getId(), equalTo(1L));
+ assertThat(response.getName(), equalTo("Book 1"));
+ }
+
+ @Test
+ public void testPostBookWithChapters() {
+ final Book book = new Book("Book 1", 1L);
+ book.addChapter(1L, "Chapter 1");
+ book.addChapter(2L, "Chapter 2");
+
+ final Book response = createWebClient("/bookstore2/books")
+ .header("Content-Type", MediaType.APPLICATION_JSON)
+ .post(book)
+ .readEntity(Book.class);
+ assertThat(response.getId(), equalTo(1L));
+ assertThat(response.getName(), equalTo("Book 1"));
+ assertThat(response.getChapters().size(), equalTo(2));
+ }
+
+ @Test
+ public void testPostAndGetBook() {
+ testPostBook();
+
+ final Book book = createWebClient("/bookstore2/books/1").get(Book.class);
+ assertThat(book.getId(), equalTo(1L));
+ assertThat(book.getName(), equalTo("Book 1"));
+ assertThat(book.getChapters(), hasItems());
+ }
+
+ @Test
+ public void testPostAndGetBooks() {
+ testPostBookWithChapters();
+
+ final Book[] books = createWebClient("/bookstore2/books").get(Book[].class);
+ assertThat(books.length, equalTo(1));
+ assertThat(books[0].getId(), equalTo(1L));
+ assertThat(books[0].getName(), equalTo("Book 1"));
+ assertThat(books[0].getChapters().size(), equalTo(2));
+ }
+
+ @Test
+ public void testGetBook() {
+ final Book book = createWebClient("/bookstore2/books/100").get(Book.class);
+ assertThat(book, nullValue());
+ }
+
+ private static WebClient createWebClient(final String url) {
+ return WebClient
+ .create("http://localhost:" + PORT + url,
+ Arrays.< Object >asList(new JsrJsonbProvider()))
+ .accept(MediaType.APPLICATION_JSON);
+ }
+
+}