From a5902b2fdde685b7c78b419d2592f53f447a0ebb Mon Sep 17 00:00:00 2001 From: Kuba Antosik Date: Fri, 25 Sep 2020 21:43:49 +1000 Subject: [PATCH] Create RESTEasy Jackson codestart --- .../resteasy-jackson-example/base/README.md | 3 ++ .../resteasy-jackson-example/codestart.yml | 12 +++++ .../java/org/acme/resteasyjackson/Fruit.java | 14 ++++++ .../FruitObjectMapperCustomizer.java | 16 ++++++ .../acme/resteasyjackson/FruitResource.java | 38 ++++++++++++++ .../NativeFruitResourceIT.java | 9 ++++ .../resteasyjackson/FruitResourceTest.java | 50 +++++++++++++++++++ .../kotlin/org/acme/resteasyjackson/Fruit.kt | 3 ++ .../FruitObjectMapperCustomizer.kt | 13 +++++ .../org/acme/resteasyjackson/FruitResource.kt | 31 ++++++++++++ .../resteasyjackson/NativeFruitResourceIT.kt | 6 +++ .../acme/resteasyjackson/FruitResourceTest.kt | 48 ++++++++++++++++++ .../resources/META-INF/quarkus-extension.yaml | 1 + .../tools/codestarts/README.adoc | 4 ++ 14 files changed, 248 insertions(+) create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/base/README.md create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/codestart.yml create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/Fruit.java create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitObjectMapperCustomizer.java create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitResource.java create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/native-test/java/org/acme/resteasyjackson/NativeFruitResourceIT.java create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/test/java/org/acme/resteasyjackson/FruitResourceTest.java create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/Fruit.kt create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitObjectMapperCustomizer.kt create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitResource.kt create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/native-test/kotlin/org/acme/resteasyjackson/NativeFruitResourceIT.kt create mode 100644 devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/test/kotlin/org/acme/resteasyjackson/FruitResourceTest.kt diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/base/README.md b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/base/README.md new file mode 100644 index 0000000000000..ef862ca6cca71 --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/base/README.md @@ -0,0 +1,3 @@ +== RESTEasy JSON serialisation using Jackson + +Guide: https://quarkus.io/guides/rest-json diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/codestart.yml b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/codestart.yml new file mode 100644 index 0000000000000..97eb23d4db3bd --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/codestart.yml @@ -0,0 +1,12 @@ +name: resteasy-jackson-example +ref: resteasy-jackson +type: code +tags: example +language: + base: + dependencies: + - io.quarkus:quarkus-resteasy + - io.quarkus:quarkus-resteasy-jackson + test-dependencies: + - io.rest-assured:rest-assured + diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/Fruit.java b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/Fruit.java new file mode 100644 index 0000000000000..435241bac9a8d --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/Fruit.java @@ -0,0 +1,14 @@ +package org.acme.resteasyjackson; + +public class Fruit { + public String name; + public String description; + + public Fruit() { + } + + public Fruit(String name, String description) { + this.name = name; + this.description = description; + } +} diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitObjectMapperCustomizer.java b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitObjectMapperCustomizer.java new file mode 100644 index 0000000000000..a8640c60f3b4e --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitObjectMapperCustomizer.java @@ -0,0 +1,16 @@ +package org.acme.resteasyjackson; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.jackson.ObjectMapperCustomizer; + +import javax.inject.Singleton; + +@Singleton +public class FruitObjectMapperCustomizer implements ObjectMapperCustomizer { + + @Override + public void customize(ObjectMapper objectMapper) { + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } +} diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitResource.java b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitResource.java new file mode 100644 index 0000000000000..24af090dbe3c3 --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson/FruitResource.java @@ -0,0 +1,38 @@ +package org.acme.resteasyjackson; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Set; + +@Path("/resteasy-jackson/fruits") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class FruitResource { + + private final Set fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>())); + + public FruitResource() { + fruits.add(new Fruit("Apple", "Winter fruit")); + fruits.add(new Fruit("Pineapple", "Tropical fruit")); + fruits.add(new Fruit("Strawberry", null)); + } + + @GET + public Set list() { + return fruits; + } + + @POST + public Set add(Fruit fruit) { + fruits.add(fruit); + return fruits; + } + + @DELETE + public Set delete(Fruit fruit) { + fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name)); + return fruits; + } +} \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/native-test/java/org/acme/resteasyjackson/NativeFruitResourceIT.java b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/native-test/java/org/acme/resteasyjackson/NativeFruitResourceIT.java new file mode 100644 index 0000000000000..620292f2226a8 --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/native-test/java/org/acme/resteasyjackson/NativeFruitResourceIT.java @@ -0,0 +1,9 @@ +package org.acme.resteasyjackson; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class NativeFruitResourceIT extends FruitResourceTest { + + // Execute the same tests but in native mode. +} \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/test/java/org/acme/resteasyjackson/FruitResourceTest.java b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/test/java/org/acme/resteasyjackson/FruitResourceTest.java new file mode 100644 index 0000000000000..ce4f2de7f2a12 --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/test/java/org/acme/resteasyjackson/FruitResourceTest.java @@ -0,0 +1,50 @@ +package org.acme.resteasyjackson; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +import javax.ws.rs.core.MediaType; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.containsInAnyOrder; + +@QuarkusTest +public class FruitResourceTest { + + @Test + public void testList() { + given() + .when().get("/resteasy-jackson/fruits") + .then() + .statusCode(200) + .body("$.size()", is(3), + "name", containsInAnyOrder("Apple", "Pineapple", "Strawberry"), + "description", containsInAnyOrder("Winter fruit", "Tropical fruit", null)); + } + + @Test + public void testAdd() { + given() + .body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}") + .header("Content-Type", MediaType.APPLICATION_JSON) + .when() + .post("/resteasy-jackson/fruits") + .then() + .statusCode(200) + .body("$.size()", is(4), + "name", containsInAnyOrder("Apple", "Pineapple", "Strawberry", "Pear"), + "description", containsInAnyOrder("Winter fruit", "Tropical fruit", null, "Winter fruit")); + + given() + .body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}") + .header("Content-Type", MediaType.APPLICATION_JSON) + .when() + .delete("/resteasy-jackson/fruits") + .then() + .statusCode(200) + .body("$.size()", is(3), + "name", containsInAnyOrder("Apple", "Pineapple", "Strawberry"), + "description", containsInAnyOrder("Winter fruit", "Tropical fruit", null)); + } +} \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/Fruit.kt b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/Fruit.kt new file mode 100644 index 0000000000000..908a2762d1c1b --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/Fruit.kt @@ -0,0 +1,3 @@ +package org.acme.resteasyjackson + +data class Fruit(val name: String, val description: String?) diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitObjectMapperCustomizer.kt b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitObjectMapperCustomizer.kt new file mode 100644 index 0000000000000..04892274d0812 --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitObjectMapperCustomizer.kt @@ -0,0 +1,13 @@ +package org.acme.resteasyjackson + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.ObjectMapper +import io.quarkus.jackson.ObjectMapperCustomizer +import javax.inject.Singleton + +@Singleton +class FruitObjectMapperCustomizer : ObjectMapperCustomizer { + override fun customize(objectMapper: ObjectMapper) { + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) + } +} \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitResource.kt b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitResource.kt new file mode 100644 index 0000000000000..15001d4aa2333 --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/main/kotlin/org/acme/resteasyjackson/FruitResource.kt @@ -0,0 +1,31 @@ +package org.acme.resteasyjackson + +import javax.ws.rs.* +import javax.ws.rs.core.MediaType + +@Path("/resteasy-jackson/fruits") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +class FruitResource { + + private val fruits: MutableSet = mutableSetOf( + Fruit("Apple", "Winter fruit"), + Fruit("Pineapple", "Tropical fruit"), + Fruit("Strawberry", null) + ) + + @GET + fun list() = fruits + + @POST + fun add(fruit: Fruit): Set { + fruits.add(fruit) + return fruits + } + + @DELETE + fun delete(fruit: Fruit): Set { + fruits.removeIf { existingFruit: Fruit -> existingFruit.name.contentEquals(fruit.name) } + return fruits + } +} \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/native-test/kotlin/org/acme/resteasyjackson/NativeFruitResourceIT.kt b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/native-test/kotlin/org/acme/resteasyjackson/NativeFruitResourceIT.kt new file mode 100644 index 0000000000000..cfad22ad275fd --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/native-test/kotlin/org/acme/resteasyjackson/NativeFruitResourceIT.kt @@ -0,0 +1,6 @@ +package org.acme.resteasyjackson + +import io.quarkus.test.junit.NativeImageTest + +@NativeImageTest +class NativeFruitResourceIT : FruitResourceTest() \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/test/kotlin/org/acme/resteasyjackson/FruitResourceTest.kt b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/test/kotlin/org/acme/resteasyjackson/FruitResourceTest.kt new file mode 100644 index 0000000000000..bdc5754c552bf --- /dev/null +++ b/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/kotlin/src/test/kotlin/org/acme/resteasyjackson/FruitResourceTest.kt @@ -0,0 +1,48 @@ +package org.acme.resteasyjackson + +import io.quarkus.test.junit.QuarkusTest +import io.restassured.RestAssured.given +import org.hamcrest.CoreMatchers.`is` +import org.hamcrest.Matchers +import org.junit.jupiter.api.Test +import javax.ws.rs.core.MediaType + +@QuarkusTest +class FruitResourceTest { + + @Test + fun testList() { + given() + .`when`()["/resteasy-jackson/fruits"] + .then() + .statusCode(200) + .body("$.size()", `is`(3), + "name", Matchers.containsInAnyOrder("Apple", "Pineapple", "Strawberry"), + "description", Matchers.containsInAnyOrder("Winter fruit", "Tropical fruit", null)) + } + + @Test + fun testAdd() { + given() + .body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}") + .header("Content-Type", MediaType.APPLICATION_JSON) + .`when`() + .post("/resteasy-jackson/fruits") + .then() + .statusCode(200) + .body("$.size()", `is`(4), + "name", Matchers.containsInAnyOrder("Apple", "Pineapple", "Strawberry", "Pear"), + "description", Matchers.containsInAnyOrder("Winter fruit", "Tropical fruit", null, "Winter fruit")) + given() + .body("{\"name\": \"Pear\", \"description\": \"Winter fruit\"}") + .header("Content-Type", MediaType.APPLICATION_JSON) + .`when`() + .delete("/resteasy-jackson/fruits") + .then() + .statusCode(200) + .body("$.size()", `is`(3), + "name", Matchers.containsInAnyOrder("Apple", "Pineapple", "Strawberry"), + "description", Matchers.containsInAnyOrder("Winter fruit", "Tropical fruit", null)) + } + +} \ No newline at end of file diff --git a/extensions/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml index f59d95a577687..6a59997a346b0 100644 --- a/extensions/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml +++ b/extensions/resteasy-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -13,3 +13,4 @@ metadata: - "web" - "serialization" status: "stable" + codestart: "resteasy-jackson" diff --git a/independent-projects/tools/codestarts/README.adoc b/independent-projects/tools/codestarts/README.adoc index 77bdf3cf5eb3d..9b1e852b65e97 100644 --- a/independent-projects/tools/codestarts/README.adoc +++ b/independent-projects/tools/codestarts/README.adoc @@ -8,6 +8,8 @@ This guide explains how to create and configure a Quarkus Codestart for an exten Codestarts provide a personalized Quarkus getting started experience and really show the Quarkus breadth. A Quarkus extension are able to provide one or more well defined codestarts which will contain the necessary resources and code examples required to get started using that particular extension. +See here to get an understanding what new quickstarts are: https://code.quarkus.io/[https://code.quarkus.io/]. + == How it works There are two kinds of codestarts contributing to the generation of a project, the kind where we want to have only one for a project (called Base) and the rest (called Extra). @@ -223,3 +225,5 @@ The Foo Example shows... - Write the config in `src/main/resources/application.yml`. It is going to be merged with the other codestarts config and automatically converted to the selected config type (yaml or properties). - you can add languages independently +- It is much easier to create a new Quarkus project in a separate directory: write code and tests, +make sure the build passes, then copy needed files to `codestarts/` directory.