Przejdź do głównej zawartości

Tworzymy obiekt POJO na podstawie odpowiedzi JSON

· 5 min aby przeczytać
Tworzymy obiekt POJO na podstawie odpowiedzi JSON

Tworzymy obiekt Java na podstawie odpowiedzi w formacie JSON zwróconej z zewnętrznego interfejsu RESTful API.

Skąd wzięła się potrzeba generowania POJO?

Korzystając z dowolnego interfejsu RESTful API otrzymujemy w odpowiedzi obiekt zapisany w formacie JSON (ang. JavaScript Object Notation). Aby przetworzyć informacje zawarte w obiekcie JSON musimy dokonać mapowania tej odpowiedzi na obiekt POJO (ang. Plain Old Java Object). W rezultacie dostajemy proste obiekty zawierające pola oraz metody dostępowe (stery oraz getery). Należy pamiętać, że w obiektach POJO nie umieszczamy logiki biznesowej.

Generowanie POJO na podstawie JSON

W celu wygenerowania struktury obiektów POJO możemy skorzystać z darmowego narzędzia dostępnego online Plain Old Java Object. Po umieszczeniu przykładowej odpowiedzi lub schematu JSON otrzymujemy kod Java, który reprezentuje strukturę obiektów zawartych w odpowiedzi.

Załóżmy, że chcemy pobrać zawartość playlisty za pomocą YouTube API. W tym celu musimy wysłać odpowiednio spreparowane żądanie HTTP metodą GET.

https://www.googleapis.com/youtube/v3/playlistItems?playlistId=PL8A2F4D823A7D2E49&maxResults=5&part=snippet%2CcontentDetails%20&fields=nextPageToken,items(snippet(title,resourceId(videoId)))&key={YOUR_API_KEY}

W odpowiedzi dostajemy obiekt JSON o następującej treści:

{
"nextPageToken":"CAUQAA",
"items":[
{
"snippet":{
"title":"Słoń - Ugly Kid Słoń | Prod. Bent, deki DJ Flip (OFICJALNY TELEDYSK)",
"resourceId":{
"videoId":"xj7PWNS1I8k"
}
}
},
{
"snippet":{
"title":"06. Słoń - #Negatywnyrap | bit/skrecze TheReturners (OFICJALNY ODSŁUCH)",
"resourceId":{
"videoId":"BNS6n6iZ_HY"
}
}
},
{
"snippet":{
"title":"AK-47 - Jeden Krok",
"resourceId":{
"videoId":"ScjViSj6jiE"
}
}
},
{
"snippet":{
"title":"AK-47 - Znów igrasz z losem (OFFICIAL VIDEO)",
"resourceId":{
"videoId":"31GJngZbwUQ"
}
}
},
{
"snippet":{
"title":"17 Chada & Pih - Odbierz , to do Ciebie ( O NAS DLA WAS )",
"resourceId":{
"videoId":"Cc65GijorfM"
}
}
}
]
}

Teraz korzystając z narzędzia Plain Old Java Object, generujemy strukturę obiektów Java, a dokładniej mówiąc klasy, ponieważ obiekt jest reprezentacja klasy w programowaniu obiektowym.

Wygląd narzędzia "JSON schema to 2 POJO"
Wygląd narzędzia "JSON schema to 2 POJO"

Narzędzie JSON schema 2 POJO wygenerowało 5 obiektów: YouTubeResponse, Item, ResourceId oraz Snippet.

YouTubeResponse.java
package pl.devtomek.domain;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"nextPageToken",
"items"
})
public class YouTubeResponse {

@JsonProperty("nextPageToken")
private String nextPageToken;
@JsonProperty("items")
private List<Item> items = null;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("nextPageToken")
public String getNextPageToken() {
return nextPageToken;
}

@JsonProperty("nextPageToken")
public void setNextPageToken(String nextPageToken) {
this.nextPageToken = nextPageToken;
}

@JsonProperty("items")
public List<Item> getItems() {
return items;
}

@JsonProperty("items")
public void setItems(List<Item> items) {
this.items = items;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
Item.java
package pl.devtomek.domain;

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"snippet"
})
public class Item {

@JsonProperty("snippet")
private Snippet snippet;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("snippet")
public Snippet getSnippet() {
return snippet;
}

@JsonProperty("snippet")
public void setSnippet(Snippet snippet) {
this.snippet = snippet;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
ResourceId.java
package pl.devtomek.domain;

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"videoId"
})
public class ResourceId {

@JsonProperty("videoId")
private String videoId;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("videoId")
public String getVideoId() {
return videoId;
}

@JsonProperty("videoId")
public void setVideoId(String videoId) {
this.videoId = videoId;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}
Snippet.java
package pl.devtomek.domain;

import com.fasterxml.jackson.annotation.*;

import java.util.HashMap;
import java.util.Map;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"resourceId",
"title"
})
public class Snippet {

@JsonProperty("resourceId")
private ResourceId resourceId;
@JsonProperty("title")
private String title;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("resourceId")
public ResourceId getResourceId() {
return resourceId;
}

@JsonProperty("resourceId")
public void setResourceId(ResourceId resourceId) {
this.resourceId = resourceId;
}

@JsonProperty("title")
public String getTitle() {
return title;
}

@JsonProperty("title")
public void setTitle(String title) {
this.title = title;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

Teraz możemy dokonać mapowania odpowiedź JSON na obiekt JAVA. W tym celu należy skorzystać z metody createParser() obiektu JsonFactory oraz readValues() obiektu ObjectMapper, dostępnych w pakiecie com.fasterxml.jackson.core.*. Poniżej zamieściłem przykładową strukturę metody, która generuje listę obiektów YouTubeResponse na podstawie odpowiedzi JSON.

public static List<YouTubeResponse> getYouTubeResponseList(String jsonResponse) throws IOException {

JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper();

JsonParser jsonParser = factory.createParser(jsonResponse);

MappingIterator<YouTubeResponse> youTubeResponse = mapper.readValues(jsonParser, YouTubeResponse.class);

List<YouTubeResponse> youTubeResponseList = youTubeResponse.readAll();

return youTubeResponseList;
}

Ostatecznie otrzymujemy obiekty, które mogą być dalej przetwarzane przez logikę naszego programu. Należy zwrócić uwagę, że metody rzucają wyjątek w momencie niepowodzenia podczas mapowania obiektu JSON na obiekt JAVA. Logika naszego programu musi to uwzględniać i odpowiednio reagować w takiej sytuacji, ponieważ w przeciwnym wypadku pojawi się wyjątek NullPointerException podczas próby odczytu pól obiektu.

Dodawanie zależności Maven

Aby mieć dostęp do obiektów znajdujących się w pakiecie Jackson musimy dodać odpowiednie zależności w naszym pliku pom.xml.

pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>

Teraz możemy już zaimportować niezbędne pakiety w naszej aplikacji. Przed skopiowaniem powyższych zależności warto sprawdzić, czy podane wersje nie są już przestarzałe.