Tworzymy obiekt POJO na podstawie odpowiedzi JSON

Posted on 28 September, 2018 at 14:05

Tags: Java


Tworzymy obiekt POJO na podstawie odpowiedzi JSON

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.

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);
    }

}
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);
    }

}
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);
    }

}
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.

<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.


Please provide a valid nick.
Please provide a valid content.

* These fields are required.