Skip to content

Commit

Permalink
Create RESTEasy Jackson codestart
Browse files Browse the repository at this point in the history
  • Loading branch information
jantosi committed Oct 10, 2020
1 parent 11e6a90 commit f36944e
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
== RESTEasy JSON serialisation using Jackson

Guide: https://quarkus.io/guides/rest-json
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<Fruit> 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<Fruit> list() {
return fruits;
}

@POST
public Set<Fruit> add(Fruit fruit) {
fruits.add(fruit);
return fruits;
}

@DELETE
public Set<Fruit> delete(Fruit fruit) {
fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
return fruits;
}
}
Original file line number Diff line number Diff line change
@@ -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.
}
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.acme.resteasyjackson

data class Fruit(val name: String, val description: String?)
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -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<Fruit> = mutableSetOf(
Fruit("Apple", "Winter fruit"),
Fruit("Pineapple", "Tropical fruit"),
Fruit("Strawberry", null)
)

@GET
fun list() = fruits

@POST
fun add(fruit: Fruit): Set<Fruit> {
fruits.add(fruit)
return fruits
}

@DELETE
fun delete(fruit: Fruit): Set<Fruit> {
fruits.removeIf { existingFruit: Fruit -> existingFruit.name.contentEquals(fruit.name) }
return fruits
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.acme.resteasyjackson

import io.quarkus.test.junit.NativeImageTest

@NativeImageTest
class NativeFruitResourceIT : FruitResourceTest()
Original file line number Diff line number Diff line change
@@ -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))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ metadata:
- "web"
- "serialization"
status: "stable"
codestart: "resteasy-jackson"
4 changes: 4 additions & 0 deletions independent-projects/tools/codestarts/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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.

0 comments on commit f36944e

Please sign in to comment.