Consuming a RESTful web service

duration 25 minutes

Prerequisites:

Explore how to access a simple RESTful web service and consume its resources in Java using JSON-B and JSON-P.

What you’ll learn

artists.json

 1[
 2    {
 3        "name" : "foo",
 4        "albums" : [
 5            {
 6                "title" : "album_one",
 7                "artist" : "foo",
 8                "ntracks" : 12
 9            },
10            {
11                "title" : "album_two",
12                "artist" : "foo",
13                "ntracks" : 15
14            }
15        ]
16    },
17    {
18        "name" : "bar",
19        "albums" : [
20            {
21                "title" : "foo walks into a bar",
22                "artist" : "bar",
23                "ntracks" : 12
24            }
25        ]
26    },
27    {
28        "name" : "dj",
29        "albums" : [
30        ]
31    }
32]

You will learn how to access a REST service, serialize a Java object that contains a list of artists and their albums, and use two different approaches to deserialize the returned JSON resources. The first approach consists of using the Java API for JSON Binding (JSON-B) to directly convert JSON messages into Java objects. The second approach consists of using the Java API for JSON Processing (JSON-P) to process the JSON.

The REST service that provides the artists and albums resources has already been written for you and is accessible at the following link when the server is running http://localhost:9080/artists, which responds with the artists.json.

You will implement the following two endpoints using the two deserialization approaches:

  • …​/artists/total to return the total number of artists in the JSON

  • …​/artists/total/<artist> to return the total number of albums in the JSON for the particular artist

If you are interested in learning more about REST services and how you can write them, read Creating a RESTful web service.

Getting started

The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:

git clone https://github.com/openliberty/guide-rest-client-java.git
cd guide-rest-client-java

The start directory contains the starting project that you will build upon.

The finish directory contains the finished project that you will build.

Starting the service

Navigate to the start directory to begin.

This guide is already setup with a general application. As you progress through the guide, you will update the code directly and automatically see the results by using development mode.

Start Open Liberty in development mode, which starts the Open Liberty server and listens for file changes:

mvn liberty:dev

When the server is running, you can find your service at the http://localhost:9080/artists URL.

Creating POJOs

Artist.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest.model;
14
15import javax.json.bind.annotation.JsonbCreator;
16import javax.json.bind.annotation.JsonbProperty;
17import javax.json.bind.annotation.JsonbTransient;
18
19// tag::Artist[]
20public class Artist {
21    // tag::name[]
22    public String name;
23    // end::name[]
24    // tag::Albums[]
25    public Album albums[];
26    // end::Albums[]
27
28    // Object property that does not map to a JSON
29    // tag::JsonbTransient[]
30    @JsonbTransient
31    // end::JsonbTransient[]
32    public boolean legendary = true;
33
34    public Artist() {
35
36    }
37
38    // tag::JsonbCreator[]
39    @JsonbCreator
40    // end::JsonbCreator[]
41    public Artist(
42      // tag::JsonbProperty[]
43      @JsonbProperty("name") String name,
44      @JsonbProperty("albums") Album albums[]) {
45      // end::JsonbProperty[]
46
47      this.name = name;
48      this.albums = albums;
49    }
50
51    @Override
52    public String toString() {
53      return name + " wrote " + albums.length + " albums";
54    }
55}
56// end::Artist[]

Album.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest.model;
14
15import javax.json.bind.annotation.JsonbCreator;
16import javax.json.bind.annotation.JsonbProperty;
17
18// tag::Album[]
19public class Album {
20    // tag::title[]
21    public String title;
22    // end::title[]
23
24    @JsonbProperty("artist")
25    // tag::artistName[]
26    public String artistName;
27    // end::artistName[]
28
29    @JsonbProperty("ntracks")
30    // tag::totalTracks[]
31    public int totalTracks;
32    // end::totalTracks[]
33
34    public Album() {
35    }
36
37    @JsonbCreator
38    public Album(
39      @JsonbProperty("title") String title,
40      @JsonbProperty("artist") String artistName,
41      @JsonbProperty("ntracks") int totalTracks) {
42
43      this.title = title;
44      this.artistName = artistName;
45      this.totalTracks = totalTracks;
46    }
47
48    @Override
49    public String toString() {
50      return "Album titled " + title + " by " + artistName +
51        " contains " + totalTracks + " tracks";
52    }
53}
54// end::Album[]

To deserialize a JSON message, start with creating Plain Old Java Objects (POJOs) that represent what is in the JSON and whose instance members map to the keys in the JSON.

For the purpose of this guide, you are given two POJOs. The Artist object has two instance members name and albums, which map to the artist name and the collection of the albums they have written. The Album object represents a single object within the album collection, and contains three instance members title, artistName, and totalTracks, which map to the album title, the artist who wrote the album, and the number of tracks the album contains.

Introducing JSON-B and JSON-P

JSON-B is a feature introduced with Java EE 8 and strengthens Java support for JSON. With JSON-B you directly serialize and deserialize POJOs. This API gives you a variety of options for working with JSON resources.

In contrast, you need to use helper methods with JSON-P to process a JSON response. This tactic is more straightforward, but it can be cumbersome with more complex classes.

JSON-B is built on top of the existing JSON-P API. JSON-B can do everything that JSON-P can do and allows for more customization for serializing and deserializing.

Using JSON-B

Artist.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest.model;
14
15import javax.json.bind.annotation.JsonbCreator;
16import javax.json.bind.annotation.JsonbProperty;
17import javax.json.bind.annotation.JsonbTransient;
18
19// tag::Artist[]
20public class Artist {
21    // tag::name[]
22    public String name;
23    // end::name[]
24    // tag::Albums[]
25    public Album albums[];
26    // end::Albums[]
27
28    // Object property that does not map to a JSON
29    // tag::JsonbTransient[]
30    @JsonbTransient
31    // end::JsonbTransient[]
32    public boolean legendary = true;
33
34    public Artist() {
35
36    }
37
38    // tag::JsonbCreator[]
39    @JsonbCreator
40    // end::JsonbCreator[]
41    public Artist(
42      // tag::JsonbProperty[]
43      @JsonbProperty("name") String name,
44      @JsonbProperty("albums") Album albums[]) {
45      // end::JsonbProperty[]
46
47      this.name = name;
48      this.albums = albums;
49    }
50
51    @Override
52    public String toString() {
53      return name + " wrote " + albums.length + " albums";
54    }
55}
56// end::Artist[]

JSON-B requires a POJO to have a public default no-argument constructor for deserialization and binding to work properly.

The JSON-B engine includes a set of default mapping rules, which can be run without any customization annotations or custom configuration. In some instances, you might find it useful to deserialize a JSON message with only certain fields, specific field names, or classes with custom constructors. In these cases, annotations are necessary and recommended:

  • The @JsonbProperty annotation to map JSON keys to class instance members and vice versa. Without the use of this annotation, JSON-B will attempt to do POJO mapping, matching the keys in the JSON to the class instance members by name. JSON-B will attempt to match the JSON key with a Java field or method annotated with @JsonbProperty where the value in the annotation exactly matches the JSON key. If no annotation exists with the given JSON key, JSON-B will attempt to find a matching field with the same name. If no match is found, JSON-B attempts to find a matching getter method for serialization or a matching setter method for de-serialization. A match occurs when the property name of the method matches the JSON key. If no matching getter or setter method is found, serialization or de-serialization, respectively, fails with an exception. The Artist POJO does not require this annotation because all instance members match the JSON keys by name.

  • The @JsonbCreator and @JsonbProperty annotations to annotate a custom constructor. These annotations are required for proper parameter substitution when a custom constructor is used.

  • The @JsonbTransient annotation to define an object property that does not map to a JSON property. While the use of this annotation is good practice, it is only necessary for serialization.

For more information on customization with JSON-B, see the official JSON-B site.

Consuming the REST resource

Artist.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest.model;
14
15import javax.json.bind.annotation.JsonbCreator;
16import javax.json.bind.annotation.JsonbProperty;
17import javax.json.bind.annotation.JsonbTransient;
18
19// tag::Artist[]
20public class Artist {
21    // tag::name[]
22    public String name;
23    // end::name[]
24    // tag::Albums[]
25    public Album albums[];
26    // end::Albums[]
27
28    // Object property that does not map to a JSON
29    // tag::JsonbTransient[]
30    @JsonbTransient
31    // end::JsonbTransient[]
32    public boolean legendary = true;
33
34    public Artist() {
35
36    }
37
38    // tag::JsonbCreator[]
39    @JsonbCreator
40    // end::JsonbCreator[]
41    public Artist(
42      // tag::JsonbProperty[]
43      @JsonbProperty("name") String name,
44      @JsonbProperty("albums") Album albums[]) {
45      // end::JsonbProperty[]
46
47      this.name = name;
48      this.albums = albums;
49    }
50
51    @Override
52    public String toString() {
53      return name + " wrote " + albums.length + " albums";
54    }
55}
56// end::Artist[]

Album.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest.model;
14
15import javax.json.bind.annotation.JsonbCreator;
16import javax.json.bind.annotation.JsonbProperty;
17
18// tag::Album[]
19public class Album {
20    // tag::title[]
21    public String title;
22    // end::title[]
23
24    @JsonbProperty("artist")
25    // tag::artistName[]
26    public String artistName;
27    // end::artistName[]
28
29    @JsonbProperty("ntracks")
30    // tag::totalTracks[]
31    public int totalTracks;
32    // end::totalTracks[]
33
34    public Album() {
35    }
36
37    @JsonbCreator
38    public Album(
39      @JsonbProperty("title") String title,
40      @JsonbProperty("artist") String artistName,
41      @JsonbProperty("ntracks") int totalTracks) {
42
43      this.title = title;
44      this.artistName = artistName;
45      this.totalTracks = totalTracks;
46    }
47
48    @Override
49    public String toString() {
50      return "Album titled " + title + " by " + artistName +
51        " contains " + totalTracks + " tracks";
52    }
53}
54// end::Album[]

Consumer.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest;
14
15import java.util.List;
16import java.util.stream.Collectors;
17
18import javax.json.JsonArray;
19import javax.json.JsonObject;
20import javax.ws.rs.client.Client;
21import javax.ws.rs.client.ClientBuilder;
22import javax.ws.rs.core.Response;
23
24import io.openliberty.guides.consumingrest.model.Album;
25import io.openliberty.guides.consumingrest.model.Artist;
26
27// tag::Consumer[]
28public class Consumer {
29    // tag::consumeWithJsonb[]
30    public static Artist[] consumeWithJsonb(String targetUrl) {
31      Client client = ClientBuilder.newClient();
32      // tag::get-1[]
33      Response response = client.target(targetUrl).request().get();
34      // end::get-1[]
35      // tag::readEntity[]
36      Artist[] artists = response.readEntity(Artist[].class);
37      // end::readEntity[]
38
39      response.close();
40      client.close();
41
42      return artists;
43    }
44    // end::consumeWithJsonb[]
45
46    // tag::consumeWithJsonp[]
47    public static Artist[] consumeWithJsonp(String targetUrl) {
48      Client client = ClientBuilder.newClient();
49      // tag::get-2[]
50      Response response = client.target(targetUrl).request().get();
51      // end::get-2[]
52      JsonArray arr = response.readEntity(JsonArray.class);
53
54      response.close();
55      client.close();
56
57      return Consumer.collectArtists(arr);
58    }
59    // end::consumeWithJsonp[]
60
61    // tag::collectArtists[]
62    private static Artist[] collectArtists(JsonArray artistArr) {
63      List<Artist> artists = artistArr.stream().map(artistJson -> {
64        JsonArray albumArr = ((JsonObject) artistJson).getJsonArray("albums");
65        Artist artist = new Artist(
66          ((JsonObject) artistJson).getString("name"),
67          Consumer.collectAlbums(albumArr));
68        return artist;
69      }).collect(Collectors.toList());
70
71      return artists.toArray(new Artist[artists.size()]);
72    }
73    // end::collectArtists[]
74
75    // tag::collectAlbums[]
76    private static Album[] collectAlbums(JsonArray albumArr) {
77      List<Album> albums = albumArr.stream().map(albumJson -> {
78        Album album = new Album(
79          ((JsonObject) albumJson).getString("title"),
80          ((JsonObject) albumJson).getString("artist"),
81          ((JsonObject) albumJson).getInt("ntracks") );
82        return album;
83      }).collect(Collectors.toList());
84
85      return albums.toArray(new Album[albums.size()]);
86    }
87    // end::collectAlbums[]
88}
89// end::Consumer[]

The Artist and Album POJOs are ready for deserialization. Next, we’ll learn to consume the JSON response from your REST service.

Create the Consumer class.
src/main/java/io/openliberty/guides/consumingrest/Consumer.java

Processing JSON using JSON-B

Consumer.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest;
14
15import java.util.List;
16import java.util.stream.Collectors;
17
18import javax.json.JsonArray;
19import javax.json.JsonObject;
20import javax.ws.rs.client.Client;
21import javax.ws.rs.client.ClientBuilder;
22import javax.ws.rs.core.Response;
23
24import io.openliberty.guides.consumingrest.model.Album;
25import io.openliberty.guides.consumingrest.model.Artist;
26
27// tag::Consumer[]
28public class Consumer {
29    // tag::consumeWithJsonb[]
30    public static Artist[] consumeWithJsonb(String targetUrl) {
31      Client client = ClientBuilder.newClient();
32      // tag::get-1[]
33      Response response = client.target(targetUrl).request().get();
34      // end::get-1[]
35      // tag::readEntity[]
36      Artist[] artists = response.readEntity(Artist[].class);
37      // end::readEntity[]
38
39      response.close();
40      client.close();
41
42      return artists;
43    }
44    // end::consumeWithJsonb[]
45
46    // tag::consumeWithJsonp[]
47    public static Artist[] consumeWithJsonp(String targetUrl) {
48      Client client = ClientBuilder.newClient();
49      // tag::get-2[]
50      Response response = client.target(targetUrl).request().get();
51      // end::get-2[]
52      JsonArray arr = response.readEntity(JsonArray.class);
53
54      response.close();
55      client.close();
56
57      return Consumer.collectArtists(arr);
58    }
59    // end::consumeWithJsonp[]
60
61    // tag::collectArtists[]
62    private static Artist[] collectArtists(JsonArray artistArr) {
63      List<Artist> artists = artistArr.stream().map(artistJson -> {
64        JsonArray albumArr = ((JsonObject) artistJson).getJsonArray("albums");
65        Artist artist = new Artist(
66          ((JsonObject) artistJson).getString("name"),
67          Consumer.collectAlbums(albumArr));
68        return artist;
69      }).collect(Collectors.toList());
70
71      return artists.toArray(new Artist[artists.size()]);
72    }
73    // end::collectArtists[]
74
75    // tag::collectAlbums[]
76    private static Album[] collectAlbums(JsonArray albumArr) {
77      List<Album> albums = albumArr.stream().map(albumJson -> {
78        Album album = new Album(
79          ((JsonObject) albumJson).getString("title"),
80          ((JsonObject) albumJson).getString("artist"),
81          ((JsonObject) albumJson).getInt("ntracks") );
82        return album;
83      }).collect(Collectors.toList());
84
85      return albums.toArray(new Album[albums.size()]);
86    }
87    // end::collectAlbums[]
88}
89// end::Consumer[]

pom.xml

  1<?xml version='1.0' encoding='utf-8'?>
  2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3
  4    <modelVersion>4.0.0</modelVersion>
  5
  6    <groupId>io.openliberty.guides</groupId>
  7    <artifactId>guide-rest-client-java</artifactId>
  8    <version>1.0-SNAPSHOT</version>
  9    <packaging>war</packaging>
 10
 11    <properties>
 12        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 13        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 14        <maven.compiler.source>1.8</maven.compiler.source>
 15        <maven.compiler.target>1.8</maven.compiler.target>
 16        <failOnMissingWebXml>false</failOnMissingWebXml>
 17        <!-- Plugin versions -->
 18        <version.liberty-maven-plugin>3.1</version.liberty-maven-plugin>
 19        <version.maven-failsafe-plugin>2.22.2</version.maven-failsafe-plugin>
 20        <version.maven-war-plugin>3.2.3</version.maven-war-plugin>
 21        <version.maven-surefire-plugin>2.22.2</version.maven-surefire-plugin>
 22        <!-- Liberty configuration -->
 23        <liberty.var.default.http.port>9080</liberty.var.default.http.port>
 24        <liberty.var.default.https.port>9443</liberty.var.default.https.port>
 25    </properties>
 26
 27    <dependencies>
 28        <!-- Provided dependencies -->
 29        <!-- tag::microprofile[] -->
 30        <dependency>
 31            <groupId>org.eclipse.microprofile</groupId>
 32            <artifactId>microprofile</artifactId>
 33            <version>3.0</version>
 34            <type>pom</type>
 35            <scope>provided</scope>
 36        </dependency>
 37        <!-- end::microprofile[] -->
 38        <!-- For tests -->
 39        <dependency>
 40            <groupId>org.junit.jupiter</groupId>
 41            <artifactId>junit-jupiter-engine</artifactId>
 42            <version>5.5.2</version>
 43            <scope>test</scope>
 44        </dependency>
 45        <dependency>
 46            <groupId>org.apache.cxf</groupId>
 47            <artifactId>cxf-rt-rs-client</artifactId>
 48            <version>3.3.4</version>
 49            <scope>test</scope>
 50        </dependency>
 51        <!-- JSON-P RI -->
 52        <dependency>
 53            <groupId>org.glassfish</groupId>
 54            <artifactId>javax.json</artifactId>
 55            <version>1.1.4</version>
 56            <scope>test</scope>
 57        </dependency>
 58        <!-- JSON-B API -->
 59        <!-- tag::Yasson[] -->
 60        <dependency>
 61            <groupId>org.eclipse</groupId>
 62            <artifactId>yasson</artifactId>
 63            <version>1.0.5</version>
 64            <scope>test</scope>
 65        </dependency>
 66        <!-- end::Yasson[] -->
 67        <!-- Support for JDK 9 and above -->
 68        <dependency>
 69            <groupId>javax.xml.bind</groupId>
 70            <artifactId>jaxb-api</artifactId>
 71            <version>2.3.1</version>
 72            <scope>test</scope>
 73        </dependency>
 74    </dependencies>
 75
 76    <build>
 77        <finalName>${project.artifactId}</finalName>
 78        <plugins>
 79            <plugin>
 80                <groupId>org.apache.maven.plugins</groupId>
 81                <artifactId>maven-war-plugin</artifactId>
 82                <version>${version.maven-war-plugin}</version>
 83            </plugin>
 84            <!-- Plugin to run unit tests -->
 85            <plugin>
 86                <groupId>org.apache.maven.plugins</groupId>
 87                <artifactId>maven-surefire-plugin</artifactId>
 88                <version>${version.maven-surefire-plugin}</version>
 89            </plugin>
 90            <!-- Enable liberty-maven plugin -->
 91            <plugin>
 92                <groupId>io.openliberty.tools</groupId>
 93                <artifactId>liberty-maven-plugin</artifactId>
 94                <version>${version.liberty-maven-plugin}</version>
 95            </plugin>
 96            <!-- Plugin to run functional tests -->
 97            <plugin>
 98                <groupId>org.apache.maven.plugins</groupId>
 99                <artifactId>maven-failsafe-plugin</artifactId>
100                <version>${version.maven-failsafe-plugin}</version>
101                <configuration>
102                    <systemPropertyVariables>
103                        <http.port>${liberty.var.default.http.port}</http.port>
104                    </systemPropertyVariables>
105                </configuration>
106            </plugin>
107        </plugins>
108    </build>
109</project>

JSON-B is a Java API that is used to serialize Java objects to JSON messages and vice versa.

Open Liberty’s JSON-B feature on Maven Central includes the JSON-B provider through transitive dependencies. The JSON-B APIs are provided by the MicroProfile dependency in your pom.xml file. Look for the dependency with the microprofile artifact ID.

The consumeWithJsonb() method in the Consumer class makes a GET request to the running artist service and retrieves the JSON. To bind the JSON into an Artist array, use the Artist[] entity type in the readEntity call.

Processing JSON using JSON-P

Consumer.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest;
14
15import java.util.List;
16import java.util.stream.Collectors;
17
18import javax.json.JsonArray;
19import javax.json.JsonObject;
20import javax.ws.rs.client.Client;
21import javax.ws.rs.client.ClientBuilder;
22import javax.ws.rs.core.Response;
23
24import io.openliberty.guides.consumingrest.model.Album;
25import io.openliberty.guides.consumingrest.model.Artist;
26
27// tag::Consumer[]
28public class Consumer {
29    // tag::consumeWithJsonb[]
30    public static Artist[] consumeWithJsonb(String targetUrl) {
31      Client client = ClientBuilder.newClient();
32      // tag::get-1[]
33      Response response = client.target(targetUrl).request().get();
34      // end::get-1[]
35      // tag::readEntity[]
36      Artist[] artists = response.readEntity(Artist[].class);
37      // end::readEntity[]
38
39      response.close();
40      client.close();
41
42      return artists;
43    }
44    // end::consumeWithJsonb[]
45
46    // tag::consumeWithJsonp[]
47    public static Artist[] consumeWithJsonp(String targetUrl) {
48      Client client = ClientBuilder.newClient();
49      // tag::get-2[]
50      Response response = client.target(targetUrl).request().get();
51      // end::get-2[]
52      JsonArray arr = response.readEntity(JsonArray.class);
53
54      response.close();
55      client.close();
56
57      return Consumer.collectArtists(arr);
58    }
59    // end::consumeWithJsonp[]
60
61    // tag::collectArtists[]
62    private static Artist[] collectArtists(JsonArray artistArr) {
63      List<Artist> artists = artistArr.stream().map(artistJson -> {
64        JsonArray albumArr = ((JsonObject) artistJson).getJsonArray("albums");
65        Artist artist = new Artist(
66          ((JsonObject) artistJson).getString("name"),
67          Consumer.collectAlbums(albumArr));
68        return artist;
69      }).collect(Collectors.toList());
70
71      return artists.toArray(new Artist[artists.size()]);
72    }
73    // end::collectArtists[]
74
75    // tag::collectAlbums[]
76    private static Album[] collectAlbums(JsonArray albumArr) {
77      List<Album> albums = albumArr.stream().map(albumJson -> {
78        Album album = new Album(
79          ((JsonObject) albumJson).getString("title"),
80          ((JsonObject) albumJson).getString("artist"),
81          ((JsonObject) albumJson).getInt("ntracks") );
82        return album;
83      }).collect(Collectors.toList());
84
85      return albums.toArray(new Album[albums.size()]);
86    }
87    // end::collectAlbums[]
88}
89// end::Consumer[]

The consumeWithJsonp() method in the Consumer class makes a GET request to the running artist service and retrieves the JSON. This method then uses the collectArtists and collectAlbums helper methods. These helper methods will parse the JSON and collect its objects into individual POJOs. Notice that you can use the custom constructors to create instances of Artist and Album.

Creating additional REST resources

Consumer.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest;
14
15import java.util.List;
16import java.util.stream.Collectors;
17
18import javax.json.JsonArray;
19import javax.json.JsonObject;
20import javax.ws.rs.client.Client;
21import javax.ws.rs.client.ClientBuilder;
22import javax.ws.rs.core.Response;
23
24import io.openliberty.guides.consumingrest.model.Album;
25import io.openliberty.guides.consumingrest.model.Artist;
26
27// tag::Consumer[]
28public class Consumer {
29    // tag::consumeWithJsonb[]
30    public static Artist[] consumeWithJsonb(String targetUrl) {
31      Client client = ClientBuilder.newClient();
32      // tag::get-1[]
33      Response response = client.target(targetUrl).request().get();
34      // end::get-1[]
35      // tag::readEntity[]
36      Artist[] artists = response.readEntity(Artist[].class);
37      // end::readEntity[]
38
39      response.close();
40      client.close();
41
42      return artists;
43    }
44    // end::consumeWithJsonb[]
45
46    // tag::consumeWithJsonp[]
47    public static Artist[] consumeWithJsonp(String targetUrl) {
48      Client client = ClientBuilder.newClient();
49      // tag::get-2[]
50      Response response = client.target(targetUrl).request().get();
51      // end::get-2[]
52      JsonArray arr = response.readEntity(JsonArray.class);
53
54      response.close();
55      client.close();
56
57      return Consumer.collectArtists(arr);
58    }
59    // end::consumeWithJsonp[]
60
61    // tag::collectArtists[]
62    private static Artist[] collectArtists(JsonArray artistArr) {
63      List<Artist> artists = artistArr.stream().map(artistJson -> {
64        JsonArray albumArr = ((JsonObject) artistJson).getJsonArray("albums");
65        Artist artist = new Artist(
66          ((JsonObject) artistJson).getString("name"),
67          Consumer.collectAlbums(albumArr));
68        return artist;
69      }).collect(Collectors.toList());
70
71      return artists.toArray(new Artist[artists.size()]);
72    }
73    // end::collectArtists[]
74
75    // tag::collectAlbums[]
76    private static Album[] collectAlbums(JsonArray albumArr) {
77      List<Album> albums = albumArr.stream().map(albumJson -> {
78        Album album = new Album(
79          ((JsonObject) albumJson).getString("title"),
80          ((JsonObject) albumJson).getString("artist"),
81          ((JsonObject) albumJson).getInt("ntracks") );
82        return album;
83      }).collect(Collectors.toList());
84
85      return albums.toArray(new Album[albums.size()]);
86    }
87    // end::collectAlbums[]
88}
89// end::Consumer[]

ArtistResource.java

 1// tag::comment[]
 2/*******************************************************************************
 3 * Copyright (c) 2018 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License v1.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-v10.html
 8 *
 9 * Contributors:
10 *     IBM Corporation - initial API and implementation
11 *******************************************************************************/
12 // end::comment[]
13package io.openliberty.guides.consumingrest.service;
14
15import javax.json.JsonArray;
16import javax.json.bind.Jsonb;
17import javax.json.bind.JsonbBuilder;
18import javax.ws.rs.GET;
19import javax.ws.rs.Path;
20import javax.ws.rs.PathParam;
21import javax.ws.rs.Produces;
22import javax.ws.rs.core.Context;
23import javax.ws.rs.core.MediaType;
24import javax.ws.rs.core.UriInfo;
25
26import io.openliberty.guides.consumingrest.model.Artist;
27import io.openliberty.guides.consumingrest.Consumer;
28
29@Path("artists")
30// tag::ArtistResource[]
31public class ArtistResource {
32
33    @Context
34    UriInfo uriInfo;
35
36    @GET
37    @Produces(MediaType.APPLICATION_JSON)
38    // tag::getArtists[]
39    public JsonArray getArtists() {
40            return Reader.getArtists();
41    }
42    // end::getArtists[]
43
44    @GET
45    @Path("jsonString")
46    @Produces(MediaType.TEXT_PLAIN)
47    // tag::getJsonString[]
48    public String getJsonString() {
49      Jsonb jsonb = JsonbBuilder.create();
50
51      Artist[] artists = Consumer.consumeWithJsonb(uriInfo.getBaseUri().toString() +
52        "artists");
53      String result = jsonb.toJson(artists);
54
55      return result;
56    }
57    // end::getJsonString[]
58
59    @GET
60    @Path("total/{artist}")
61    @Produces(MediaType.TEXT_PLAIN)
62    // tag::getTotalAlbums[]
63    public int getTotalAlbums(@PathParam("artist") String artist) {
64      Artist[] artists = Consumer.consumeWithJsonb(uriInfo.getBaseUri().toString()
65        + "artists");
66
67      for (int i = 0; i < artists.length; i++) {
68        if (artists[i].name.equals(artist)) {
69          return artists[i].albums.length;
70        }
71      }
72      return -1;
73    }
74    // end::getTotalAlbums[]
75
76    @GET
77    @Path("total")
78    @Produces(MediaType.TEXT_PLAIN)
79    // tag::getTotalArtists[]
80    public int getTotalArtists() {
81      return Consumer.consumeWithJsonp(uriInfo.getBaseUri().toString() +
82        "artists").length;
83    }
84    // end::getTotalArtists[]
85}
86// end::ArtistResource[]

Now that you can consume a JSON resource you can put that data to use.

Replace the ArtistResource class.
src/main/java/io/openliberty/guides/consumingrest/service/ArtistResource.java
  • The getArtists() method provides the raw JSON data service that you accessed at the beginning of this guide.

  • The getJsonString() method uses JSON-B to return the JSON as a string that will be used later for testing.

  • The getTotalAlbums() method uses JSON-B to return the total number of albums present in the JSON for a particular artist. The method returns -1 if this artist does not exist.

  • The getTotalArtists() method uses JSON-P to return the total number of artists present in the JSON.

The methods that you wrote in the Consumer class could be written directly in the ArtistResource class. However, if you are consuming a REST resource from a third party service, you should separate your GET/POST requests from your data consumption.

Running the application

The Open Liberty server was started in development mode at the beginning of the guide and all the changes were automatically picked up.

You can find your service at http://localhost:9080/artists.

Now, you can access the endpoint at http://localhost:9080/artists/total to see the total number of artists, and you can access the endpoint at http://localhost:9080/artists/total/<artist> to see a particular artist’s total number of albums.

Testing deserialization

ConsumingRestIT.java

  1// tag::comment[]
  2/*******************************************************************************
  3 * Copyright (c) 2018, 2019 IBM Corporation and others.
  4 * All rights reserved. This program and the accompanying materials
  5 * are made available under the terms of the Eclipse Public License v1.0
  6 * which accompanies this distribution, and is available at
  7 * http://www.eclipse.org/legal/epl-v10.html
  8 *
  9 * Contributors:
 10 *     IBM Corporation - initial API and implementation
 11 *******************************************************************************/
 12 // end::comment[]
 13package it.io.openliberty.guides.consumingrest;
 14
 15import static org.junit.jupiter.api.Assertions.assertEquals;
 16
 17import javax.json.bind.Jsonb;
 18import javax.json.bind.JsonbBuilder;
 19import javax.ws.rs.client.Client;
 20import javax.ws.rs.client.ClientBuilder;
 21import javax.ws.rs.core.Response;
 22
 23import org.junit.jupiter.api.AfterEach;
 24import org.junit.jupiter.api.BeforeEach;
 25import org.junit.jupiter.api.BeforeAll;
 26import org.junit.jupiter.api.Test;
 27
 28import io.openliberty.guides.consumingrest.model.Artist;
 29
 30public class ConsumingRestIT {
 31
 32    private static String port;
 33    private static String baseUrl;
 34    private static String targetUrl;
 35
 36    private Client client;
 37    private Response response;
 38
 39    // tag::BeforeAll[]
 40    @BeforeAll
 41    // end::BeforeAll[]
 42    public static void oneTimeSetup() {
 43      port = System.getProperty("http.port");
 44      baseUrl = "http://localhost:" + port + "/artists/";
 45      targetUrl = baseUrl + "total/";
 46    }
 47
 48    // tag::BeforeEach[]
 49    @BeforeEach
 50    // end::BeforeEach[]
 51    public void setup() {
 52      client = ClientBuilder.newClient();
 53    }
 54
 55    // tag::AfterEach[]
 56    @AfterEach
 57    // end::AfterEach[]
 58    public void teardown() {
 59      client.close();
 60    }
 61
 62    // tag::test-1[]
 63    @Test
 64    // end::test-1[]
 65    // tag::testArtistDeserialization[]
 66    public void testArtistDeserialization() {
 67      response = client.target(baseUrl + "jsonString").request().get();
 68      this.assertResponse(baseUrl + "jsonString", response);
 69
 70      Jsonb jsonb = JsonbBuilder.create();
 71
 72      String expectedString = "{\"name\":\"foo\",\"albums\":"
 73        + "[{\"title\":\"album_one\",\"artist\":\"foo\",\"ntracks\":12}]}";
 74      Artist expected = jsonb.fromJson(expectedString, Artist.class);
 75
 76      String actualString = response.readEntity(String.class);
 77                  Artist[] actual = jsonb.fromJson(actualString, Artist[].class);
 78
 79      assertEquals(expected.name, actual[0].name,
 80        "Expected names of artists does not match");
 81
 82      response.close();
 83    }
 84    // end::testArtistDeserialization[]
 85
 86    // tag::test-2[]
 87    @Test
 88    // end::test-2[]
 89    // tag::testJsonBAlbumCount[]
 90    public void testJsonBAlbumCount() {
 91      String[] artists = {"dj", "bar", "foo"};
 92      for (int i = 0; i < artists.length; i++) {
 93        response = client.target(targetUrl + artists[i]).request().get();
 94        this.assertResponse(targetUrl + artists[i], response);
 95
 96        int expected = i;
 97        int actual = response.readEntity(int.class);
 98        assertEquals(expected, actual, "Album count for " + artists[i] + " does not match");
 99
100        response.close();
101      }
102    }
103    // end::testJsonBAlbumCount[]
104
105    // tag::testAlbumCountForUnknownArtist[]
106    // tag::test-3[]
107    @Test
108    // end::test-3[]
109    // tag::testJsonBAlbumCountForUnknownArtist[]
110    public void testJsonBAlbumCountForUnknownArtist() {
111      response = client.target(targetUrl + "unknown-artist").request().get();
112
113      int expected = -1;
114      int actual = response.readEntity(int.class);
115      assertEquals(expected, actual, "Unknown artist must have -1 albums");
116
117      response.close();
118    }
119    // end::testJsonBAlbumCountForUnknownArtist[]
120
121    // tag::test-4[]
122    @Test
123    // end::test-4[]
124    // tag::testJsonPArtistCount[]
125    public void testJsonPArtistCount() {
126      response = client.target(targetUrl).request().get();
127      this.assertResponse(targetUrl, response);
128
129      int expected = 3;
130      int actual = response.readEntity(int.class);
131      assertEquals(expected, actual, "Expected number of artists does not match");
132
133      response.close();
134    }
135    // end::testJsonPArtistCount[]
136
137    /**
138     * Asserts that the given URL has the correct (200) response code.
139     */
140    // tag::assertResponse[]
141    private void assertResponse(String url, Response response) {
142      assertEquals(200, response.getStatus(), "Incorrect response code from " + url);
143    }
144    // end::assertResponse[]
145    // end::tests[]
146}
Create the ConsumingRestIT class.
src/test/java/it/io/openliberty/guides/consumingrest/ConsumingRestIT.java

Maven finds and executes all tests under the src/test/java/it/ directory, and each test method must be marked with the @Test annotation.

You can use the @BeforeAll and @AfterAll annotations to perform any one-time setup and teardown tasks before and after all of your tests run. You can also use the @BeforeEach and @AfterEach annotations to perform setup and teardown tasks for individual test cases.

Testing the binding process

ConsumingRestIT.java

  1// tag::comment[]
  2/*******************************************************************************
  3 * Copyright (c) 2018, 2019 IBM Corporation and others.
  4 * All rights reserved. This program and the accompanying materials
  5 * are made available under the terms of the Eclipse Public License v1.0
  6 * which accompanies this distribution, and is available at
  7 * http://www.eclipse.org/legal/epl-v10.html
  8 *
  9 * Contributors:
 10 *     IBM Corporation - initial API and implementation
 11 *******************************************************************************/
 12 // end::comment[]
 13package it.io.openliberty.guides.consumingrest;
 14
 15import static org.junit.jupiter.api.Assertions.assertEquals;
 16
 17import javax.json.bind.Jsonb;
 18import javax.json.bind.JsonbBuilder;
 19import javax.ws.rs.client.Client;
 20import javax.ws.rs.client.ClientBuilder;
 21import javax.ws.rs.core.Response;
 22
 23import org.junit.jupiter.api.AfterEach;
 24import org.junit.jupiter.api.BeforeEach;
 25import org.junit.jupiter.api.BeforeAll;
 26import org.junit.jupiter.api.Test;
 27
 28import io.openliberty.guides.consumingrest.model.Artist;
 29
 30public class ConsumingRestIT {
 31
 32    private static String port;
 33    private static String baseUrl;
 34    private static String targetUrl;
 35
 36    private Client client;
 37    private Response response;
 38
 39    // tag::BeforeAll[]
 40    @BeforeAll
 41    // end::BeforeAll[]
 42    public static void oneTimeSetup() {
 43      port = System.getProperty("http.port");
 44      baseUrl = "http://localhost:" + port + "/artists/";
 45      targetUrl = baseUrl + "total/";
 46    }
 47
 48    // tag::BeforeEach[]
 49    @BeforeEach
 50    // end::BeforeEach[]
 51    public void setup() {
 52      client = ClientBuilder.newClient();
 53    }
 54
 55    // tag::AfterEach[]
 56    @AfterEach
 57    // end::AfterEach[]
 58    public void teardown() {
 59      client.close();
 60    }
 61
 62    // tag::test-1[]
 63    @Test
 64    // end::test-1[]
 65    // tag::testArtistDeserialization[]
 66    public void testArtistDeserialization() {
 67      response = client.target(baseUrl + "jsonString").request().get();
 68      this.assertResponse(baseUrl + "jsonString", response);
 69
 70      Jsonb jsonb = JsonbBuilder.create();
 71
 72      String expectedString = "{\"name\":\"foo\",\"albums\":"
 73        + "[{\"title\":\"album_one\",\"artist\":\"foo\",\"ntracks\":12}]}";
 74      Artist expected = jsonb.fromJson(expectedString, Artist.class);
 75
 76      String actualString = response.readEntity(String.class);
 77                  Artist[] actual = jsonb.fromJson(actualString, Artist[].class);
 78
 79      assertEquals(expected.name, actual[0].name,
 80        "Expected names of artists does not match");
 81
 82      response.close();
 83    }
 84    // end::testArtistDeserialization[]
 85
 86    // tag::test-2[]
 87    @Test
 88    // end::test-2[]
 89    // tag::testJsonBAlbumCount[]
 90    public void testJsonBAlbumCount() {
 91      String[] artists = {"dj", "bar", "foo"};
 92      for (int i = 0; i < artists.length; i++) {
 93        response = client.target(targetUrl + artists[i]).request().get();
 94        this.assertResponse(targetUrl + artists[i], response);
 95
 96        int expected = i;
 97        int actual = response.readEntity(int.class);
 98        assertEquals(expected, actual, "Album count for " + artists[i] + " does not match");
 99
100        response.close();
101      }
102    }
103    // end::testJsonBAlbumCount[]
104
105    // tag::testAlbumCountForUnknownArtist[]
106    // tag::test-3[]
107    @Test
108    // end::test-3[]
109    // tag::testJsonBAlbumCountForUnknownArtist[]
110    public void testJsonBAlbumCountForUnknownArtist() {
111      response = client.target(targetUrl + "unknown-artist").request().get();
112
113      int expected = -1;
114      int actual = response.readEntity(int.class);
115      assertEquals(expected, actual, "Unknown artist must have -1 albums");
116
117      response.close();
118    }
119    // end::testJsonBAlbumCountForUnknownArtist[]
120
121    // tag::test-4[]
122    @Test
123    // end::test-4[]
124    // tag::testJsonPArtistCount[]
125    public void testJsonPArtistCount() {
126      response = client.target(targetUrl).request().get();
127      this.assertResponse(targetUrl, response);
128
129      int expected = 3;
130      int actual = response.readEntity(int.class);
131      assertEquals(expected, actual, "Expected number of artists does not match");
132
133      response.close();
134    }
135    // end::testJsonPArtistCount[]
136
137    /**
138     * Asserts that the given URL has the correct (200) response code.
139     */
140    // tag::assertResponse[]
141    private void assertResponse(String url, Response response) {
142      assertEquals(200, response.getStatus(), "Incorrect response code from " + url);
143    }
144    // end::assertResponse[]
145    // end::tests[]
146}

pom.xml

  1<?xml version='1.0' encoding='utf-8'?>
  2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3
  4    <modelVersion>4.0.0</modelVersion>
  5
  6    <groupId>io.openliberty.guides</groupId>
  7    <artifactId>guide-rest-client-java</artifactId>
  8    <version>1.0-SNAPSHOT</version>
  9    <packaging>war</packaging>
 10
 11    <properties>
 12        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 13        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 14        <maven.compiler.source>1.8</maven.compiler.source>
 15        <maven.compiler.target>1.8</maven.compiler.target>
 16        <failOnMissingWebXml>false</failOnMissingWebXml>
 17        <!-- Plugin versions -->
 18        <version.liberty-maven-plugin>3.1</version.liberty-maven-plugin>
 19        <version.maven-failsafe-plugin>2.22.2</version.maven-failsafe-plugin>
 20        <version.maven-war-plugin>3.2.3</version.maven-war-plugin>
 21        <version.maven-surefire-plugin>2.22.2</version.maven-surefire-plugin>
 22        <!-- Liberty configuration -->
 23        <liberty.var.default.http.port>9080</liberty.var.default.http.port>
 24        <liberty.var.default.https.port>9443</liberty.var.default.https.port>
 25    </properties>
 26
 27    <dependencies>
 28        <!-- Provided dependencies -->
 29        <!-- tag::microprofile[] -->
 30        <dependency>
 31            <groupId>org.eclipse.microprofile</groupId>
 32            <artifactId>microprofile</artifactId>
 33            <version>3.0</version>
 34            <type>pom</type>
 35            <scope>provided</scope>
 36        </dependency>
 37        <!-- end::microprofile[] -->
 38        <!-- For tests -->
 39        <dependency>
 40            <groupId>org.junit.jupiter</groupId>
 41            <artifactId>junit-jupiter-engine</artifactId>
 42            <version>5.5.2</version>
 43            <scope>test</scope>
 44        </dependency>
 45        <dependency>
 46            <groupId>org.apache.cxf</groupId>
 47            <artifactId>cxf-rt-rs-client</artifactId>
 48            <version>3.3.4</version>
 49            <scope>test</scope>
 50        </dependency>
 51        <!-- JSON-P RI -->
 52        <dependency>
 53            <groupId>org.glassfish</groupId>
 54            <artifactId>javax.json</artifactId>
 55            <version>1.1.4</version>
 56            <scope>test</scope>
 57        </dependency>
 58        <!-- JSON-B API -->
 59        <!-- tag::Yasson[] -->
 60        <dependency>
 61            <groupId>org.eclipse</groupId>
 62            <artifactId>yasson</artifactId>
 63            <version>1.0.5</version>
 64            <scope>test</scope>
 65        </dependency>
 66        <!-- end::Yasson[] -->
 67        <!-- Support for JDK 9 and above -->
 68        <dependency>
 69            <groupId>javax.xml.bind</groupId>
 70            <artifactId>jaxb-api</artifactId>
 71            <version>2.3.1</version>
 72            <scope>test</scope>
 73        </dependency>
 74    </dependencies>
 75
 76    <build>
 77        <finalName>${project.artifactId}</finalName>
 78        <plugins>
 79            <plugin>
 80                <groupId>org.apache.maven.plugins</groupId>
 81                <artifactId>maven-war-plugin</artifactId>
 82                <version>${version.maven-war-plugin}</version>
 83            </plugin>
 84            <!-- Plugin to run unit tests -->
 85            <plugin>
 86                <groupId>org.apache.maven.plugins</groupId>
 87                <artifactId>maven-surefire-plugin</artifactId>
 88                <version>${version.maven-surefire-plugin}</version>
 89            </plugin>
 90            <!-- Enable liberty-maven plugin -->
 91            <plugin>
 92                <groupId>io.openliberty.tools</groupId>
 93                <artifactId>liberty-maven-plugin</artifactId>
 94                <version>${version.liberty-maven-plugin}</version>
 95            </plugin>
 96            <!-- Plugin to run functional tests -->
 97            <plugin>
 98                <groupId>org.apache.maven.plugins</groupId>
 99                <artifactId>maven-failsafe-plugin</artifactId>
100                <version>${version.maven-failsafe-plugin}</version>
101                <configuration>
102                    <systemPropertyVariables>
103                        <http.port>${liberty.var.default.http.port}</http.port>
104                    </systemPropertyVariables>
105                </configuration>
106            </plugin>
107        </plugins>
108    </build>
109</project>

The yasson dependency was added in your pom.xml file so that your test classes have access to JSON-B.

The testArtistDeserialization test case checks that Artist instances created from the REST data and those that are hardcoded perform the same.

The assertResponse helper method ensures that the response code you receive is valid (200).

Processing with JSON-B test

ConsumingRestIT.java

  1// tag::comment[]
  2/*******************************************************************************
  3 * Copyright (c) 2018, 2019 IBM Corporation and others.
  4 * All rights reserved. This program and the accompanying materials
  5 * are made available under the terms of the Eclipse Public License v1.0
  6 * which accompanies this distribution, and is available at
  7 * http://www.eclipse.org/legal/epl-v10.html
  8 *
  9 * Contributors:
 10 *     IBM Corporation - initial API and implementation
 11 *******************************************************************************/
 12 // end::comment[]
 13package it.io.openliberty.guides.consumingrest;
 14
 15import static org.junit.jupiter.api.Assertions.assertEquals;
 16
 17import javax.json.bind.Jsonb;
 18import javax.json.bind.JsonbBuilder;
 19import javax.ws.rs.client.Client;
 20import javax.ws.rs.client.ClientBuilder;
 21import javax.ws.rs.core.Response;
 22
 23import org.junit.jupiter.api.AfterEach;
 24import org.junit.jupiter.api.BeforeEach;
 25import org.junit.jupiter.api.BeforeAll;
 26import org.junit.jupiter.api.Test;
 27
 28import io.openliberty.guides.consumingrest.model.Artist;
 29
 30public class ConsumingRestIT {
 31
 32    private static String port;
 33    private static String baseUrl;
 34    private static String targetUrl;
 35
 36    private Client client;
 37    private Response response;
 38
 39    // tag::BeforeAll[]
 40    @BeforeAll
 41    // end::BeforeAll[]
 42    public static void oneTimeSetup() {
 43      port = System.getProperty("http.port");
 44      baseUrl = "http://localhost:" + port + "/artists/";
 45      targetUrl = baseUrl + "total/";
 46    }
 47
 48    // tag::BeforeEach[]
 49    @BeforeEach
 50    // end::BeforeEach[]
 51    public void setup() {
 52      client = ClientBuilder.newClient();
 53    }
 54
 55    // tag::AfterEach[]
 56    @AfterEach
 57    // end::AfterEach[]
 58    public void teardown() {
 59      client.close();
 60    }
 61
 62    // tag::test-1[]
 63    @Test
 64    // end::test-1[]
 65    // tag::testArtistDeserialization[]
 66    public void testArtistDeserialization() {
 67      response = client.target(baseUrl + "jsonString").request().get();
 68      this.assertResponse(baseUrl + "jsonString", response);
 69
 70      Jsonb jsonb = JsonbBuilder.create();
 71
 72      String expectedString = "{\"name\":\"foo\",\"albums\":"
 73        + "[{\"title\":\"album_one\",\"artist\":\"foo\",\"ntracks\":12}]}";
 74      Artist expected = jsonb.fromJson(expectedString, Artist.class);
 75
 76      String actualString = response.readEntity(String.class);
 77                  Artist[] actual = jsonb.fromJson(actualString, Artist[].class);
 78
 79      assertEquals(expected.name, actual[0].name,
 80        "Expected names of artists does not match");
 81
 82      response.close();
 83    }
 84    // end::testArtistDeserialization[]
 85
 86    // tag::test-2[]
 87    @Test
 88    // end::test-2[]
 89    // tag::testJsonBAlbumCount[]
 90    public void testJsonBAlbumCount() {
 91      String[] artists = {"dj", "bar", "foo"};
 92      for (int i = 0; i < artists.length; i++) {
 93        response = client.target(targetUrl + artists[i]).request().get();
 94        this.assertResponse(targetUrl + artists[i], response);
 95
 96        int expected = i;
 97        int actual = response.readEntity(int.class);
 98        assertEquals(expected, actual, "Album count for " + artists[i] + " does not match");
 99
100        response.close();
101      }
102    }
103    // end::testJsonBAlbumCount[]
104
105    // tag::testAlbumCountForUnknownArtist[]
106    // tag::test-3[]
107    @Test
108    // end::test-3[]
109    // tag::testJsonBAlbumCountForUnknownArtist[]
110    public void testJsonBAlbumCountForUnknownArtist() {
111      response = client.target(targetUrl + "unknown-artist").request().get();
112
113      int expected = -1;
114      int actual = response.readEntity(int.class);
115      assertEquals(expected, actual, "Unknown artist must have -1 albums");
116
117      response.close();
118    }
119    // end::testJsonBAlbumCountForUnknownArtist[]
120
121    // tag::test-4[]
122    @Test
123    // end::test-4[]
124    // tag::testJsonPArtistCount[]
125    public void testJsonPArtistCount() {
126      response = client.target(targetUrl).request().get();
127      this.assertResponse(targetUrl, response);
128
129      int expected = 3;
130      int actual = response.readEntity(int.class);
131      assertEquals(expected, actual, "Expected number of artists does not match");
132
133      response.close();
134    }
135    // end::testJsonPArtistCount[]
136
137    /**
138     * Asserts that the given URL has the correct (200) response code.
139     */
140    // tag::assertResponse[]
141    private void assertResponse(String url, Response response) {
142      assertEquals(200, response.getStatus(), "Incorrect response code from " + url);
143    }
144    // end::assertResponse[]
145    // end::tests[]
146}

The testJsonBAlbumCount and testJsonBAlbumCountForUnknownArtist tests both use the total/{artist} endpoint which invokes JSON-B.

The testJsonBAlbumCount test case checks that deserialization with JSON-B was done correctly and that the correct number of albums is returned for each artist in the JSON.

The testJsonBAlbumCountForUnknownArtist test case is similar to testJsonBAlbumCount but instead checks an artist that does not exist in the JSON and ensures that a value of -1 is returned.

Processing with JSON-P test

ConsumingRestIT.java

  1// tag::comment[]
  2/*******************************************************************************
  3 * Copyright (c) 2018, 2019 IBM Corporation and others.
  4 * All rights reserved. This program and the accompanying materials
  5 * are made available under the terms of the Eclipse Public License v1.0
  6 * which accompanies this distribution, and is available at
  7 * http://www.eclipse.org/legal/epl-v10.html
  8 *
  9 * Contributors:
 10 *     IBM Corporation - initial API and implementation
 11 *******************************************************************************/
 12 // end::comment[]
 13package it.io.openliberty.guides.consumingrest;
 14
 15import static org.junit.jupiter.api.Assertions.assertEquals;
 16
 17import javax.json.bind.Jsonb;
 18import javax.json.bind.JsonbBuilder;
 19import javax.ws.rs.client.Client;
 20import javax.ws.rs.client.ClientBuilder;
 21import javax.ws.rs.core.Response;
 22
 23import org.junit.jupiter.api.AfterEach;
 24import org.junit.jupiter.api.BeforeEach;
 25import org.junit.jupiter.api.BeforeAll;
 26import org.junit.jupiter.api.Test;
 27
 28import io.openliberty.guides.consumingrest.model.Artist;
 29
 30public class ConsumingRestIT {
 31
 32    private static String port;
 33    private static String baseUrl;
 34    private static String targetUrl;
 35
 36    private Client client;
 37    private Response response;
 38
 39    // tag::BeforeAll[]
 40    @BeforeAll
 41    // end::BeforeAll[]
 42    public static void oneTimeSetup() {
 43      port = System.getProperty("http.port");
 44      baseUrl = "http://localhost:" + port + "/artists/";
 45      targetUrl = baseUrl + "total/";
 46    }
 47
 48    // tag::BeforeEach[]
 49    @BeforeEach
 50    // end::BeforeEach[]
 51    public void setup() {
 52      client = ClientBuilder.newClient();
 53    }
 54
 55    // tag::AfterEach[]
 56    @AfterEach
 57    // end::AfterEach[]
 58    public void teardown() {
 59      client.close();
 60    }
 61
 62    // tag::test-1[]
 63    @Test
 64    // end::test-1[]
 65    // tag::testArtistDeserialization[]
 66    public void testArtistDeserialization() {
 67      response = client.target(baseUrl + "jsonString").request().get();
 68      this.assertResponse(baseUrl + "jsonString", response);
 69
 70      Jsonb jsonb = JsonbBuilder.create();
 71
 72      String expectedString = "{\"name\":\"foo\",\"albums\":"
 73        + "[{\"title\":\"album_one\",\"artist\":\"foo\",\"ntracks\":12}]}";
 74      Artist expected = jsonb.fromJson(expectedString, Artist.class);
 75
 76      String actualString = response.readEntity(String.class);
 77                  Artist[] actual = jsonb.fromJson(actualString, Artist[].class);
 78
 79      assertEquals(expected.name, actual[0].name,
 80        "Expected names of artists does not match");
 81
 82      response.close();
 83    }
 84    // end::testArtistDeserialization[]
 85
 86    // tag::test-2[]
 87    @Test
 88    // end::test-2[]
 89    // tag::testJsonBAlbumCount[]
 90    public void testJsonBAlbumCount() {
 91      String[] artists = {"dj", "bar", "foo"};
 92      for (int i = 0; i < artists.length; i++) {
 93        response = client.target(targetUrl + artists[i]).request().get();
 94        this.assertResponse(targetUrl + artists[i], response);
 95
 96        int expected = i;
 97        int actual = response.readEntity(int.class);
 98        assertEquals(expected, actual, "Album count for " + artists[i] + " does not match");
 99
100        response.close();
101      }
102    }
103    // end::testJsonBAlbumCount[]
104
105    // tag::testAlbumCountForUnknownArtist[]
106    // tag::test-3[]
107    @Test
108    // end::test-3[]
109    // tag::testJsonBAlbumCountForUnknownArtist[]
110    public void testJsonBAlbumCountForUnknownArtist() {
111      response = client.target(targetUrl + "unknown-artist").request().get();
112
113      int expected = -1;
114      int actual = response.readEntity(int.class);
115      assertEquals(expected, actual, "Unknown artist must have -1 albums");
116
117      response.close();
118    }
119    // end::testJsonBAlbumCountForUnknownArtist[]
120
121    // tag::test-4[]
122    @Test
123    // end::test-4[]
124    // tag::testJsonPArtistCount[]
125    public void testJsonPArtistCount() {
126      response = client.target(targetUrl).request().get();
127      this.assertResponse(targetUrl, response);
128
129      int expected = 3;
130      int actual = response.readEntity(int.class);
131      assertEquals(expected, actual, "Expected number of artists does not match");
132
133      response.close();
134    }
135    // end::testJsonPArtistCount[]
136
137    /**
138     * Asserts that the given URL has the correct (200) response code.
139     */
140    // tag::assertResponse[]
141    private void assertResponse(String url, Response response) {
142      assertEquals(200, response.getStatus(), "Incorrect response code from " + url);
143    }
144    // end::assertResponse[]
145    // end::tests[]
146}

The testJsonPArtistCount test uses the total endpoint which invokes JSON-P. This test checks that deserialization with JSON-P was done correctly and that the correct number of artists is returned.

Running the tests

Since you started Open Liberty in development mode at the start of the guide, press the enter/return key to run the tests.

If the tests pass, you see a similar output to the following example:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.consumingrest.ConsumingRestIT
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.59 sec - in it.io.openliberty.guides.consumingrest.ConsumingRestIT

Results :

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

When you are done checking out the service, exit development mode by typing q in the shell session where you ran the server, and then press the enter/return key.

Building the application

If you are satisfied with your application, run the Maven package goal to build the WAR file in the target directory:

mvn package

Great work! You’re done!

You just accessed a simple RESTful web service and consumed its resources by using JSON-B and JSON-P in Open Liberty.

Guide Attribution

Consuming a RESTful web service by Open Liberty is licensed under CC BY-ND 4.0

Copied to clipboard
Copy code block
Copy file contents

Prerequisites:

Nice work! Where to next?

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

Like Open Liberty? Star our repo on GitHub.

Star