В этой статье показано, как вернуть JSON ответ в приложении Джерси , используя Jackson 2.x .
Протестировано с
- Джерси 3.0.2
- HTTP-сервер Grizzly 3
- Джексон 2.12.2
- Java 11
- Знаток
- JUnit 5 и JSONassert 1.5 (Модульный тест)
Содержание
- 1. Джексон как поставщик JSON в Джерси
- 2. Каталог проектов
- 3. Зависимости проекта
- 4. Конечные точки Джерси и возвращают ответ JSON
- 5. Запустите приложение Джерси
- 6. ДЕМОНСТРАЦИЯ
- 7. Пользовательский картограф объектов Джексона в Джерси
- 7.1 Включите режим печати Jackson pretty
- 7.2 Зарегистрируйте пользовательский сопоставитель объектов Джексона в ResourceConfig
- 7.3 Демонстрация с включенной симпатичной печатью
- 8. Пользовательское исключение JsonMappingException в Джерси
- 8.1 Пользовательское исключение JsonMappingException
- 8.2 Зарегистрируйте пользовательское исключение JsonMappingException в ResourceConfig
- 8.3 ДЕМОНСТРАЦИЯ с пользовательским исключением JsonMappingException
- 9. Модульное тестирование конечных точек JSON Джерси
- 10. Скачать Исходный Код
- 11. Рекомендации
1. Джексон как поставщик JSON в Джерси
Мы можем включить джерси-медиа-json-Джексон , чтобы включить Джексона в качестве поставщика JSON в приложении Джерси.
org.glassfish.jersey.media jersey-media-json-jackson
2. Каталог проектов
Просмотрите каталог стандартных проектов Maven.
3. Зависимости проекта
Просмотрите зависимости проекта.
4.0.0 com.mkyong jersey-json-example jar 1.0 UTF-8 11 11 11 5.4.0 1.5.0 3.0.2 org.glassfish.jersey jersey-bom ${jersey.version} pom import org.glassfish.jersey.containers jersey-container-grizzly2-http org.glassfish.jersey.inject jersey-hk2 org.glassfish.jersey.media jersey-media-json-jackson jakarta.activation jakarta.activation-api 2.0.1 org.junit.jupiter junit-jupiter-params ${junit.version} test org.skyscreamer jsonassert ${jsonassert.version} test jersey-json-jackson org.apache.maven.plugins maven-compiler-plugin 3.8.1 ${java.version} ${java.version} org.apache.maven.plugins maven-surefire-plugin 3.0.0-M5 org.apache.maven.plugins maven-jar-plugin 3.2.0 true lib/ com.mkyong.MainApp org.apache.maven.plugins maven-dependency-plugin 3.1.2 copy-dependencies package copy-dependencies runtime ${project.build.directory}/lib/
4. Конечные точки Джерси и возвращают ответ JSON
Создайте несколько конечных точек в Джерси, и Джексон обработает преобразование объекта из/в JSON.
4.1 Создайте следующие конечные точки и верните ответ JSON.
- GET
/json/
, возвращает строку JSON. - ПОЛУЧИТЬ
/json/{имя}
, возвращаетПользователь
объект, содержащий{имя}
в строке JSON. - ПОЛУЧИТЬ
/json/все
, возвращает списокПользовательских
объектов в строке JSON. - СООБЩЕНИЕ
/json/создать
, принимает данные JSON и возвращает статус201
.
package com.mkyong.json; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.util.Arrays; import java.util.List; @Path("/json") public class JsonResource { private static final ObjectMapper mapper = new ObjectMapper(); @GET @Produces(MediaType.APPLICATION_JSON) public Response hello() { // create a JSON string ObjectNode json = mapper.createObjectNode(); json.put("result", "Jersey JSON example using Jackson 2.x"); return Response.status(Response.Status.OK).entity(json).build(); } // Object to JSON @Path("/{name}") @GET @Produces(MediaType.APPLICATION_JSON) public User hello(@PathParam("name") String name) { return new User(1, name); } // A list of objects to JSON @Path("/all") @GET @Produces(MediaType.APPLICATION_JSON) public ListhelloList() { return Arrays.asList( new User(1, "mkyong"), new User(2, "zilap") ); } @Path("/create") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response create(User user) { ObjectNode json = mapper.createObjectNode(); json.put("status", "ok"); return Response.status(Response.Status.CREATED).entity(json).build(); } }
4.2 Ниже приведен объект User
; позже Джексон преобразует этот объект в/из строки JSON.
package com.mkyong.json; public class User { private int id; String name; public User() { } public User(int id, String name) { this.id = id; this.name = name; } // getters and setters }
5. Запустите приложение Джерси
Запускает приложение Джерси по адресу http://localhost:8080
.
package com.mkyong; import com.mkyong.json.JsonResource; import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; import org.glassfish.jersey.server.ResourceConfig; import java.io.IOException; import java.net.URI; import java.util.logging.Level; import java.util.logging.Logger; public class MainApp { public static final URI BASE_URI = URI.create("http://localhost:8080"); // Starts Grizzly HTTP server public static HttpServer startHttpServer() { final ResourceConfig config = new ResourceConfig(); config.register(JsonResource.class); // JacksonFeature for JAXB/POJO, for pure JSON, no need this JacksonFeature // config.register(JacksonFeature.class); return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, config); } public static void main(String[] args) { try { final HttpServer server = startHttpServer(); server.start(); // shut down hook Runtime.getRuntime().addShutdownHook(new Thread(server::shutdownNow)); System.out.println( String.format("Application started.%nStop the application using CTRL+C")); // block and wait shut down signal, like CTRL+C Thread.currentThread().join(); } catch (InterruptedException | IOException ex) { Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, ex); } } }
6. ДЕМОНСТРАЦИЯ
Запускает Основное приложение
и использует инструмент cURL
для простого тестирования.
$ curl http://localhost:8080/json {"result":"Jersey JSON example using Jackson 2.x"} $ curl http://localhost:8080/json/mkyong {"id":1,"name":"mkyong"} $ curl http://localhost:8080/json/all [{"id":1,"name":"mkyong"},{"id":2,"name":"zilap"}] # send a POST request with JSON data $ curl -H "Content-Type: application/json" -X POST -d "{\"id\" : 1,\"name\" : \"mkyong\"}" http://localhost:8080/json/create {"status":"ok"}
7. Пользовательский картограф объектов Джексона в Джерси
В приведенной выше демонстрации ответ JSON находится в компактном режиме, поведение по умолчанию Jackson ObjectMapper
; и мы можем создать пользовательское приложение Jackson ObjectMapper
в Джерси, реализовав класс JAX RS ContextResolver
.
7.1 Включите режим печати Jackson pretty
Ниже приведен пример, создайте пользовательский файл Jackson ObjectMapper
, чтобы включить режим красивой печати.
package com.mkyong.json; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import jakarta.ws.rs.ext.ContextResolver; import jakarta.ws.rs.ext.Provider; // enable Jackson pretty print @Provider public class CustomJacksonMapperProvider implements ContextResolver{ final ObjectMapper mapper; public CustomJacksonMapperProvider() { // enable pretty print mapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT); } @Override public ObjectMapper getContext(Class> type) { return mapper; } }
7.2 Зарегистрируйте пользовательский сопоставитель объектов Джексона в ResourceConfig
public static HttpServer startHttpServer() { final ResourceConfig config = new ResourceConfig(); config.register(JsonResource.class); // register the custom Jackson mapper config.register(CustomJacksonMapperProvider.class); return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, config); }
7.3 Демонстрация с включенной симпатичной печатью
Снова запускает Основное приложение
, и теперь ответ JSON находится в красивой строке печати.
$ curl http://localhost:8080/json/java { "id" : 1, "name" : "java" } $ curl http://localhost:8080/json/all [ { "id" : 1, "name" : "mkyong" }, { "id" : 2, "name" : "zilap" } ]
8. Пользовательское исключение JsonMappingException в Джерси
Мы пытаемся ОПУБЛИКОВАТЬ
нераспознанное поле в /json/создать
, и Джерси вернет подробное сообщение по умолчанию.
$ curl -H "Content-Type: application/json" -X POST -d "{\"id-error-field\" : 1,\"name\" : \"mkyong\"}" http://localhost:8080/json/create Unrecognized field "id-error-field" (class com.mkyong.json.User), not marked as ignorable (2 known properties: "id", "name"]) at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 22] (through reference chain: com.mkyong.json.User["id-error-field"])
8.1 Пользовательское исключение JsonMappingException
Мы можем создать пользовательский ExceptionMapper
для перехвата JsonMappingException
ошибки и возврата нашего пользовательского ответа JSON.
package com.mkyong.json; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; @Provider public class CustomJsonExceptionMapper implements ExceptionMapper{ private static final ObjectMapper mapper = new ObjectMapper(); @Override public Response toResponse(JsonMappingException exception) { ObjectNode json = mapper.createObjectNode(); //json.put("error", exception.getMessage()); json.put("error", "json mapping error"); return Response.status(Response.Status.BAD_REQUEST) .entity(json.toPrettyString()) .build(); } }
8.2 Зарегистрируйте пользовательское исключение JsonMappingException в ResourceConfig
public static HttpServer startHttpServer() { final ResourceConfig config = new ResourceConfig(); config.register(JsonResource.class); config.register(CustomJacksonMapperProvider.class); // custom ExceptionMapper config.register(CustomJsonExceptionMapper.class); return GrizzlyHttpServerFactory.createHttpServer(BASE_URI, config); }
8.3 ДЕМОНСТРАЦИЯ с пользовательским исключением JsonMappingException
Снова запускает Основное приложение
, и мы ОТПРАВЛЯЕМ
нераспознанное поле в /json/создаем
снова, и теперь Джерси вернет ваш пользовательский ответ в формате JSON.
$ curl -H "Content-Type: application/json" -X POST -d "{\"id-error-field\" : 1,\"name\" : \"mkyong\"}" http://localhost:8080/json/create { "error" : "json mapping error" }
9. Модульное тестирование конечных точек JSON Джерси
Ниже приведен JUnit 5 и JSONAssert пример для тестирования конечных точек JSON Джерси.
package com.mkyong; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.glassfish.grizzly.http.server.HttpServer; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; import static org.junit.jupiter.api.Assertions.assertEquals; public class JsonResourceTest { private static HttpServer server; private static WebTarget target; @BeforeAll public static void beforeAllTests() { server = MainApp.startHttpServer(); Client c = ClientBuilder.newClient(); target = c.target(MainApp.BASE_URI.toString()); } @AfterAll public static void afterAllTests() { server.shutdownNow(); } @Test public void testJson() throws JSONException { String actual = target.path("json").request().get(String.class); String expected = "{\"result\":\"Jersey JSON example using Jackson 2.x\"}"; JSONAssert.assertEquals(expected, actual, false); } @Test public void testJsonName() throws JSONException { String response = target.path("json/mkyong") .request(MediaType.APPLICATION_JSON) .get(String.class); // convert json string to JSONObject JSONObject actual = new JSONObject(response); String expected = "{\"id\":1,\"name\":\"mkyong\"}"; JSONAssert.assertEquals(expected, actual, false); } @Test public void testJsonAll() throws JSONException { String response = target.path("json/all") .request(MediaType.APPLICATION_JSON) .get(String.class); // convert json string to JSONArray JSONArray actual = new JSONArray(response); String expected = "[{\"id\":1,\"name\":\"mkyong\"},{\"id\":2,\"name\":\"zilap\"}]"; JSONAssert.assertEquals(expected, actual, false); } @Test public void testJsonCreateOk() throws JSONException { String json = "{\"id\":1,\"name\":\"mkyong\"}"; Response response = target.path("json/create") .request(MediaType.APPLICATION_JSON) .post(Entity.entity(json, MediaType.valueOf("application/json"))); assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); // read response body String actual = response.readEntity(String.class); String expected = "{\"status\":\"ok\"}"; JSONAssert.assertEquals(expected, actual, false); } @Test public void testJsonCreateError() throws JSONException { String json = "{\"id_no_field\":1,\"name\":\"mkyong\"}"; Response response = target.path("json/create") .request(MediaType.APPLICATION_JSON) .post(Entity.entity(json, MediaType.valueOf("application/json"))); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); String actual = response.readEntity(String.class); String expected = "{\"error\":\"json mapping error\"}"; JSONAssert.assertEquals(expected, actual, false); } }
10. Скачать Исходный Код
$клон git https://github.com/mkyong/jax-rs
$cd jax-rs/джерси/джерси-json-джексон/
$ пакет mvn
$цель java-jar/джерси-json- $цель java-jar/джерси-json-
11. Рекомендации
- Джерси Eclipse
- Поддержка Джерси и JSON
- Инъекция зависимостей Джерси и HK2 (автоматическое сканирование)
- Джерси 3x Последнее Руководство пользователя
- JSONassert – Написание модульных тестов JSON с меньшим количеством кода
- Джексон – Как включить вывод pretty print в формате JSON
- Примеры моделей Джексона–Дерева
- Завиток–СТОЛБ примеры запросов
- Джексон – Как анализировать JSON
Оригинал: “https://mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/”