Автор оригинала: mkyong.
В этой статье показано, как вернуть JSON ответ в приложении Джерси , используя EclipseLink Moxy .
Протестировано с
- Джерси 3.0.2
- EclipseLink Мокси 3
- Причал 11, HTTP-сервер
- Java 11
- Мавен 3
- SLF4J, Возврат в систему, перенаправление журналов Jersey J.U.L для возврата в систему
- JUnit 5 и JSONassert 1.5 (модульный тест)
- org.json 20210307, jsonобъект
Содержание
- 1. EclipseLink Moxy как поставщик JSON в Джерси
- 2. Каталог проектов
- 3. Зависимости проекта
- 4. Верните ответ JSON в Джерси
- 5. Запустите приложение Джерси
- 6. ДЕМОНСТРАЦИЯ
- 7. Настраиваемая конфигурация Moxy
- 8. ExceptionMapper – Пользовательский ответ JSON 404 в Джерси
- 8.1 Джерси 404 не найдено
- 8.2 Исключение и исключение NotFoundException
- 8.3 Зарегистрируйте пользовательский редактор исключений в ResourceConfig
- 8.3 ДЕМОНСТРАЦИЯ с пользовательским приложением NotFoundExceptionMapper
- 8.4 Исключение веб-приложения
- 9. Модульное тестирование конечных точек JSON Джерси
- 10. Скачать Исходный Код
- 11. Рекомендации
1. EclipseLink Moxy как поставщик JSON в Джерси
Мы можем включить джерси-медиа-мокси , чтобы сделать EclipseLink Мокси поставщиком JSON в приложении Джерси.
org.glassfish.jersey.media jersey-media-moxy
2. Каталог проектов
Просмотрите каталог стандартных проектов Maven.
3. Зависимости проекта
Просмотрите зависимости проекта.
UTF-8 11 11 11 5.4.0 1.5.0 3.0.2 1.2.3 1.7.31 20210307 5.0.0 org.glassfish.jersey jersey-bom ${jersey.version} pom import org.glassfish.jersey.containers jersey-container-jetty-http jakarta.servlet jakarta.servlet-api ${servlet.api.version} org.glassfish.jersey.inject jersey-hk2 org.glassfish.jersey.media jersey-media-moxy org.json json ${org.json.version} org.slf4j jul-to-slf4j ${slf4j.version} ch.qos.logback logback-classic ${logback.version} org.junit.jupiter junit-jupiter-params ${junit.version} test org.skyscreamer jsonassert ${jsonassert.version} test
mvn dependency:tree [INFO] Scanning for projects... [INFO] [INFO] -------------------< com.mkyong:jersey-json-example >------------------- [INFO] Building jersey-json-example 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ jersey-json-example --- [INFO] com.mkyong:jersey-json-example:jar:1.0 [INFO] +- org.glassfish.jersey.containers:jersey-container-jetty-http:jar:3.0.2:compile [INFO] | +- jakarta.inject:jakarta.inject-api:jar:2.0.0:compile [INFO] | +- org.eclipse.jetty:jetty-server:jar:11.0.0:compile [INFO] | | +- org.eclipse.jetty:jetty-http:jar:11.0.0:compile [INFO] | | \- org.eclipse.jetty:jetty-io:jar:11.0.0:compile [INFO] | +- org.eclipse.jetty:jetty-util:jar:11.0.0:compile [INFO] | +- org.glassfish.jersey.core:jersey-common:jar:3.0.2:compile [INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.0.0:compile [INFO] | | \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile [INFO] | +- org.glassfish.jersey.core:jersey-server:jar:3.0.2:compile [INFO] | | +- org.glassfish.jersey.core:jersey-client:jar:3.0.2:compile [INFO] | | \- jakarta.validation:jakarta.validation-api:jar:3.0.0:compile [INFO] | \- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.0.0:compile [INFO] +- jakarta.servlet:jakarta.servlet-api:jar:5.0.0:compile [INFO] +- org.glassfish.jersey.inject:jersey-hk2:jar:3.0.2:compile [INFO] | +- org.glassfish.hk2:hk2-locator:jar:3.0.1:compile [INFO] | | +- org.glassfish.hk2.external:aopalliance-repackaged:jar:3.0.1:compile [INFO] | | +- org.glassfish.hk2:hk2-api:jar:3.0.1:compile [INFO] | | \- org.glassfish.hk2:hk2-utils:jar:3.0.1:compile [INFO] | \- org.javassist:javassist:jar:3.25.0-GA:compile [INFO] +- org.glassfish.jersey.media:jersey-media-moxy:jar:3.0.2:compile [INFO] | +- org.glassfish.jersey.ext:jersey-entity-filtering:jar:3.0.2:compile [INFO] | +- jakarta.json:jakarta.json-api:jar:2.0.0:compile [INFO] | +- jakarta.json.bind:jakarta.json.bind-api:jar:2.0.0:compile [INFO] | +- org.glassfish:jakarta.json:jar:module:2.0.0:compile [INFO] | \- org.eclipse.persistence:org.eclipse.persistence.moxy:jar:3.0.0:compile [INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:3.0.0:compile [INFO] | +- org.eclipse.persistence:org.eclipse.persistence.asm:jar:3.0.0:compile [INFO] | +- org.eclipse.persistence:org.eclipse.persistence.core:jar:3.0.0:compile [INFO] | +- com.sun.activation:jakarta.activation:jar:2.0.0:runtime [INFO] | \- com.sun.mail:jakarta.mail:jar:2.0.0:runtime [INFO] +- org.json:json:jar:20210307:compile [INFO] +- org.slf4j:jul-to-slf4j:jar:1.7.31:compile [INFO] | \- org.slf4j:slf4j-api:jar:1.7.31:compile [INFO] +- ch.qos.logback:logback-classic:jar:1.2.3:compile [INFO] | \- ch.qos.logback:logback-core:jar:1.2.3:compile [INFO] +- org.junit.jupiter:junit-jupiter-params:jar:5.4.0:test [INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test [INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.4.0:test [INFO] | +- org.opentest4j:opentest4j:jar:1.1.1:test [INFO] | \- org.junit.platform:junit-platform-commons:jar:1.4.0:test [INFO] \- org.skyscreamer:jsonassert:jar:1.5.0:test [INFO] \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.664 s [INFO] Finished at: 2021-06-23T16:00:25+08:00 [INFO] ------------------------------------------------------------------------
4. Верните ответ JSON в Джерси
Несколько конечных точек ответа JSON в приложении Jersey, и MOXy обработает преобразование объекта в/из JSON.
package com.mkyong.json; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.json.JSONObject; import java.util.Arrays; import java.util.List; @Path("/json") public class JsonResource { @GET @Produces(MediaType.APPLICATION_JSON) public Response hello() { // create a JSON string JSONObject json = new JSONObject(); json.put("result", "Jersey JSON example using MOXy"); // MUST json.toString(), else empty result or Unconsumed content // return Response.status(Response.Status.OK).entity(json).build(); return Response.status(Response.Status.OK).entity(json.toString()).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") ); } // POST, accepts JSON @Path("/create") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response create(User user) { JSONObject json = new JSONObject(); json.put("status", "ok"); return Response.status(Response.Status.CREATED).entity(json.toString()).build(); } }
Ниже приведен объект User
.
package com.mkyong.json; // optional, for json response, no need @XmlRootElement // only needed if works with XML // @XmlRootElement public class User { private int id; String name; // getters, setters and constructors and etc }
5. Запустите приложение Джерси
Запускает HTTP-сервер Jetty и развертывает приложение Jersey по адресу http://localhost:8080
.
P.S Статическая инициализация необязательна, и она предназначена для настройки ведения журнала для перенаправления журналов J.U.L Джерси в реализацию обратного входа SLF4J.
package com.mkyong; import com.mkyong.json.JsonResource; import org.eclipse.jetty.server.Server; import org.glassfish.jersey.jetty.JettyHttpContainerFactory; import org.glassfish.jersey.server.ResourceConfig; import org.slf4j.bridge.SLF4JBridgeHandler; 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"); // For logging, setup to redirect J.U.L to logback static { // JUL Root logger to the lowest level, so that bridge can intercept all j.u.l. logs Logger.getLogger("").setLevel(Level.FINEST); // Optionally remove existing handlers attached to j.u.l root logger // (since SLF4J 1.6.5) SLF4JBridgeHandler.removeHandlersForRootLogger(); // add SLF4JBridgeHandler to j.u.l's root logger, should be done once during // the initialization phase of your application SLF4JBridgeHandler.install(); } // Starts Jetty HTTP server public static Server startHttpServer() { final ResourceConfig config = new ResourceConfig(); // scan only one resource config.register(JsonResource.class); return JettyHttpContainerFactory.createServer(BASE_URI, config); } public static void main(String[] args) throws Exception { try { final Server server = startHttpServer(); server.start(); // shut down hook Runtime.getRuntime().addShutdownHook( new Thread(() -> { try { server.stop(); } catch (Exception e) { Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, e); } }) ); 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 MOXy"} $ curl http://localhost:8080/json/jersey {"id":1,"name":"jersey"} $ curl http://localhost:8080/json/all [{"id":1,"name":"mkyong"},{"id":2,"name":"zilap"}] $ curl -v -H "Content-Type: application/json" -X POST -d "{\"id\" : 1,\"name\" : \"mkyong\"}" http://localhost:8080/json/create * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8080 (#0) > POST /json/create HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.55.1 > Accept: */* > Content-Type: application/json > Content-Length: 28 > * upload completely sent off: 28 out of 28 bytes < HTTP/1.1 201 Created < Date: Wed, 23 Jun 2021 06:48:53 GMT < Content-Type: application/json < Transfer-Encoding: chunked < Server: Jetty(11.0.0) < {"status":"ok"}*
7. Настраиваемая конфигурация Moxy
7.1 В приведенной выше демонстрации ответ JSON находится в компактном режиме, поведение MOXY по умолчанию; Мы можем создать новый MoxyJsonConfig
для настройки MOXY, например, включить JSON-ответ MOXY в красивом формате печати.
package com.mkyong.json; import jakarta.ws.rs.ext.ContextResolver; import jakarta.ws.rs.ext.Provider; import org.glassfish.jersey.moxy.json.MoxyJsonConfig; @Provider public class CustomMoxyConfig implements ContextResolver{ final MoxyJsonConfig moxyJsonConfig; public CustomMoxyConfig() { moxyJsonConfig = new MoxyJsonConfig(); // pretty print moxyJsonConfig.setFormattedOutput(true); } @Override public MoxyJsonConfig getContext(Class> type) { return moxyJsonConfig; } }
7.2 Зарегистрируйте пользовательский MoxyJsonConfig
в Настройка ресурсов
.
// Starts Jetty HTTP server public static Server startHttpServer() { final ResourceConfig config = new ResourceConfig(); // scan only one resource config.register(JsonResource.class); // only register if contains custom moxy config config.register(CustomMoxyConfig.class); return JettyHttpContainerFactory.createServer(BASE_URI, config); }
7.3 Снова перезапустите Основное приложение
, и теперь ответ JSON будет в красивом печатном формате.
$ curl http://localhost:8080/json/all [ { "id" : 1, "name" : "mkyong" }, { "id" : 2, "name" : "zilap" } ]
8. ExceptionMapper – Пользовательский ответ JSON 404 в Джерси
Позже мы создадим пользовательский ExceptionMapper
для перехвата исключения ошибки 404 по умолчанию и возврата нашего пользовательского ответа JSON.
8.1 Джерси 404 не найдено
Попробуйте получить доступ к какому-либо несуществующему URL-адресу, и Jersey вернет статус 404 и пустой ответ.
$ curl http://localhost:8080/json/all/error
Мы можем использовать curl - v
для отображения сведений о запросе и ответе, например, кода состояния ответа.
$ curl -v http://localhost:8080/json/all/error * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8080 (#0) > GET /json/all/error HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.55.1 > Accept: */* > < HTTP/1.1 404 Not Found < Date: Wed, 23 Jun 2021 07:18:01 GMT < Content-Length: 0 < Server: Jetty(11.0.0) <
8.2 Исключение и исключение NotFoundException
Создайте пользовательский сопоставитель исключений NotFoundException
для перехвата ошибки 404.
package com.mkyong.json; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import org.json.JSONObject; @Provider public class CustomNotFoundExceptionMapper implements ExceptionMapper{ @Override public Response toResponse(NotFoundException exception) { JSONObject json = new JSONObject(); json.put("error", "url not found!"); return Response.status(Response.Status.NOT_FOUND) .entity(json.toString()) .build(); } }
8.3 Зарегистрируйте пользовательский редактор исключений в ResourceConfig
// Starts Jetty HTTP server public static Server startHttpServer() { final ResourceConfig config = new ResourceConfig(); // scan only one resource config.register(JsonResource.class); // only register if contains custom moxy config config.register(CustomMoxyConfig.class); // only register if contains custom exception mapper config.register(CustomNotFoundExceptionMapper.class); return JettyHttpContainerFactory.createServer(BASE_URI, config); }
8.3 ДЕМОНСТРАЦИЯ с пользовательским приложением NotFoundExceptionMapper
Перезапустите приложение Jersey и снова получите доступ к несуществующему URL-адресу. Нью-Джерси вернет наш пользовательский ответ в формате JSON.
$ curl http://localhost:8080/json/all/error {"error":"url not found!"} $ curl -v http://localhost:8080/json/all/error * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8080 (#0) > GET /json/all/error HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.55.1 > Accept: */* > < HTTP/1.1 404 Not Found < Date: Wed, 23 Jun 2021 07:38:23 GMT < Transfer-Encoding: chunked < Server: Jetty(11.0.0) < {"error":"url not found!"}
8.4 Исключение веб-приложения
Предположим, мы не уверены в точном типе Исключения
для перехвата, и мы пытаемся перехватить исключение JAX-RS WebApplicationException
. В этом случае он должен соответствовать всем ошибкам, вызванным приложением Джерси.
По ИДЕЕ, мы можем поместить точку останова внутри в ответ
и наблюдать за тем, как приложение Джерси выдает исключения.
package com.mkyong.json; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import org.json.JSONObject; @Provider public class CustomExceptionMapper implements ExceptionMapper{ @Override public Response toResponse(WebApplicationException exception) { JSONObject json = new JSONObject(); json.put("error", exception.getMessage()); //json.put("error", "some error"); // 400 return Response.status(Response.Status.BAD_REQUEST) .entity(json.toString()) .build(); } }
Все еще не удается поймать исключение? попробуйте реализовать ExceptionMapper<Исключение>
.
9. Модульное тестирование конечных точек 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.eclipse.jetty.server.Server; 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 Server 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() throws Exception { server.stop(); } @Test public void testJson() throws JSONException { String actual = target.path("json").request().get(String.class); String expected = "{\"result\":\"Jersey JSON example using MOXy\"}"; 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 testJsonCustomNotFound() throws JSONException { Response response = target.path("json/all/error") .request(MediaType.APPLICATION_JSON).buildGet().invoke(); // ensure 404 status code assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); // test json response String actual = response.readEntity(String.class); String expected = "{\"error\":\"url not found!\"}"; JSONAssert.assertEquals(expected, actual, false); } }
Альтернатива, попробуйте Джексона |/Примеры Джерси и JSON (Джексон)
10. Скачать Исходный Код
$клон git https://github.com/mkyong/jax-rs
$cd jax-rs/джерси/джерси-json-мокси/
$ пакет mvn
$java -банка target/jersey-json-moxy.jar
11. Рекомендации
- Википедия JSON
- Джерси Eclipse
- Эклипслинк Мокси
- Поддержка Джерси и JSON
- Джерси 3x Последнее Руководство пользователя
- Пример твиттера MOXy JSON
- Указание привязок JSON
- Примеры Джерси и JSON (Джексон)
- Завиток–СТОЛБ примеры запросов
- Джексон – Как анализировать JSON
- Учебник по API ведения журнала Java
- JSONAssert – Как выполнить модульное тестирование данных JSON
Оригинал: “https://mkyong.com/webservices/jax-rs/jersey-and-json-examples-eclipselink-moxy/”