Статьи

Обработка ответа JSON с помощью нового JavaEE7 JSON-P API

Как многие знают, JCP работает над новой спецификацией для добавления обработки JSON в Java EE 7 (JSR 353). Сегодня эта спецификация стала реальностью, и здесь мы увидим, как обрабатывать JSON-ответ с помощью JsonParser низкоуровневого API для обработки больших объектов JSON.

Мы собираемся использовать общедоступный сервис Github REST, расположенный по адресу: https://api.github.com/users/[github-user]/repos . Например, репозитории DZone: https://api.github.com/users/dzone/repos 

Этот сервис возвращает объект JSON со всеми репозиториями пользователя DZone,  расположенными в Github. 

Нам нужны две внешние банки: 

  • клиент-джерси: для использования службы REST
  • javax.json: для обработки ответа JSON
Maven зависимости
<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>2.17</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.json</artifactId>
        <version>1.0.4</version>
    </dependency>
</dependencies>
Ответ JSON

[
  {
    "id": 6798716,
    "name": "AnswerHub-NewCustomer-Template",
    "full_name": "dzone/AnswerHub-NewCustomer-Template",
    "owner": {
      "login": "dzone",
      "id": 62504,
      "avatar_url": "https://avatars.githubusercontent.com/u/62504?v=3",
      "gravatar_id": "",
      "url": "https://api.github.com/users/dzone",
      "html_url": "https://github.com/dzone",
      "followers_url": "https://api.github.com/users/dzone/followers",
      "following_url": "https://api.github.com/users/dzone/following{/other_user}",
      "gists_url": "https://api.github.com/users/dzone/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/dzone/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/dzone/subscriptions",
      "organizations_url": "https://api.github.com/users/dzone/orgs",
      "repos_url": "https://api.github.com/users/dzone/repos",
      "events_url": "https://api.github.com/users/dzone/events{/privacy}",
      "received_events_url": "https://api.github.com/users/dzone/received_events",
      "type": "Organization",
      "site_admin": false
    },
    "private": false,
    "html_url": "https://github.com/dzone/AnswerHub-NewCustomer-Template",
    "description": "An example plugin to use as the foundation for building your own AnswerHub plugins.",
    "fork": false,
    "url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template",
    "forks_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/forks",
    "keys_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/keys{/key_id}",
    "collaborators_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/collaborators{/collaborator}",
    "teams_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/teams",
    "hooks_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/hooks",
    "issue_events_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/issues/events{/number}",
    "events_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/events",
    "assignees_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/assignees{/user}",
    "branches_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/branches{/branch}",
    "tags_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/tags",
    "blobs_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/git/blobs{/sha}",
    "git_tags_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/git/tags{/sha}",
    "git_refs_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/git/refs{/sha}",
    "trees_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/git/trees{/sha}",
    "statuses_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/statuses/{sha}",
    "languages_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/languages",
    "stargazers_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/stargazers",
    "contributors_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/contributors",
    "subscribers_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/subscribers",
    "subscription_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/subscription",
    "commits_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/commits{/sha}",
    "git_commits_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/git/commits{/sha}",
    "comments_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/comments{/number}",
    "issue_comment_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/issues/comments{/number}",
    "contents_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/contents/{+path}",
    "compare_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/compare/{base}...{head}",
    "merges_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/merges",
    "archive_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/{archive_format}{/ref}",
    "downloads_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/downloads",
    "issues_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/issues{/number}",
    "pulls_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/pulls{/number}",
    "milestones_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/milestones{/number}",
    "notifications_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/notifications{?since,all,participating}",
    "labels_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/labels{/name}",
    "releases_url": "https://api.github.com/repos/dzone/AnswerHub-NewCustomer-Template/releases{/id}",
    "created_at": "2012-11-21T16:13:40Z",
    "updated_at": "2013-10-21T18:08:56Z",
    "pushed_at": "2013-07-26T21:30:36Z",
    "git_url": "git://github.com/dzone/AnswerHub-NewCustomer-Template.git",
    "ssh_url": "git@github.com:dzone/AnswerHub-NewCustomer-Template.git",
    "clone_url": "https://github.com/dzone/AnswerHub-NewCustomer-Template.git",
    "svn_url": "https://github.com/dzone/AnswerHub-NewCustomer-Template",
    "homepage": null,
    "size": 64,
    "stargazers_count": 0,
    "watchers_count": 0,
    "language": null,
    "has_issues": true,
    "has_downloads": true,
    "has_wiki": true,
    "has_pages": false,
    "forks_count": 1,
    "mirror_url": null,
    "open_issues_count": 0,
    "forks": 1,
    "open_issues": 0,
    "watchers": 0,
    "default_branch": "master"
  },
  ...
]  

Первый шаг: определить модель


Нам нужно проанализировать ответ и создать классы Java, которые представляют этот ответ (модель).

Согласно ответу JSON мы должны определить две сущности: 
  • Хранилище
  • Владелец хранилища
Владелец класса
/**
 * github-rest
 *
 * Copyright 2015 "GDL Java User Group"
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package mx.gdljug.githubrest.model.pojo;

import java.io.Serializable;

/**
 * Class that represents a repository owner in github
 *
 * @author juanitodread
 * @since 1.0
 *
 * Mar 28, 2015
 */
public class Owner implements Serializable {
 
    private static final long serialVersionUID = -6503049307071107199L;
    
    private String  userName;
    private String  htmlUrl;
    private String  type;
    private boolean admin;
    
    /**
     * Instantiate a new github repository owner
     */
    public Owner(){

    }

    /**
     * Instantiate a new github repository owner
     * 
     * @param userName User name of the owner of the repo
     * @param htmlUrl  HTML URL of the owner in github
     * @param type     Github owner's types
     * @param admin    Determines whether owner is and administrator
     */
    public Owner( String userName, 
                  String htmlUrl, 
                  String type, 
                  boolean admin ) {
        this.userName = userName;
        this.htmlUrl = htmlUrl;
        this.type = type;
        this.admin = admin;
    }


    /**
     * @return the userName
     */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName the userName to set
     */
    public void setUserName( String userName ) {
        this.userName = userName;
    }

    /**
     * @return the htmlUrl
     */
    public String getHtmlUrl() {
        return htmlUrl;
    }

    /**
     * @param htmlUrl the htmlUrl to set
     */
    public void setHtmlUrl( String htmlUrl ) {
        this.htmlUrl = htmlUrl;
    }

    /**
     * @return the type
     */
    public String getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType( String type ) {
        this.type = type;
    }

    /**
     * @return the admin
     */
    public boolean isAdmin() {
        return admin;
    }

    /**
     * @param admin the admin to set
     */
    public void setAdmin( boolean admin ) {
        this.admin = admin;
    }

    /* 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format(
                "{Owner: {userName:%s, htmlUrl:%s, type:%s, admin:%s}",
                userName, htmlUrl, type, admin );
    }
    
}
Репозиторий класса
/**
 * github-rest
 *
 * Copyright 2015 "GDL Java User Group"
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package mx.gdljug.githubrest.model.pojo;

import java.io.Serializable;
import java.util.Date;

/**
 * Class that represents a repository in github
 *
 * @author juanitodread
 * @since 1.0
 *
 * Mar 28, 2015
 */
public class Repository implements Serializable {

    private static final long serialVersionUID = -8550085683718865541L;
    
    private long id;
    private String name;
    private String fullName;
    private boolean restricted; 
    private String htmlUrl;
    private String description;
    private Date created;
    private Date updated;
    private String gitUrl;
    private String language;
    private String defaultBranch;
    private Owner owner;
    
    /**
     * Instantiates a new github repository
     */
    public Repository() {
        
    }
    
    /**
     * Instantiates a new github repository
     * 
     * @param id
     * @param name
     * @param fullName
     * @param restricted
     * @param htmlUrl
     * @param description
     * @param created
     * @param updated
     * @param gitUrl
     * @param language
     * @param defaultBranch
     * @param owner
     */
    public Repository( long id,
                       String name,
                       String fullName,
                       boolean restricted,
                       String htmlUrl,
                       String description,
                       Date created,
                       Date updated,
                       String gitUrl,
                       String language,
                       String defaultBranch,
                       Owner owner ) {
        this.id = id;
        this.name = name;
        this.fullName = fullName;
        this.restricted = restricted;
        this.htmlUrl = htmlUrl;
        this.description = description;
        this.created = created;
        this.updated = updated;
        this.gitUrl = gitUrl;
        this.language = language;
        this.defaultBranch = defaultBranch;
        this.owner = owner;
    }

    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId( long id ) {
        this.id = id;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName( String name ) {
        this.name = name;
    }

    /**
     * @return the fullName
     */
    public String getFullName() {
        return fullName;
    }

    /**
     * @param fullName the fullName to set
     */
    public void setFullName( String fullName ) {
        this.fullName = fullName;
    }

    /**
     * @return the restricted
     */
    public boolean isRestricted() {
        return restricted;
    }

    /**
     * @param restricted the restricted to set
     */
    public void setRestricted( boolean restricted ) {
        this.restricted = restricted;
    }

    /**
     * @return the htmlUrl
     */
    public String getHtmlUrl() {
        return htmlUrl;
    }

    /**
     * @param htmlUrl the htmlUrl to set
     */
    public void setHtmlUrl( String htmlUrl ) {
        this.htmlUrl = htmlUrl;
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description the description to set
     */
    public void setDescription( String description ) {
        this.description = description;
    }

    /**
     * @return the created
     */
    public Date getCreated() {
        return created;
    }

    /**
     * @param created the created to set
     */
    public void setCreated( Date created ) {
        this.created = created;
    }

    /**
     * @return the updated
     */
    public Date getUpdated() {
        return updated;
    }

    /**
     * @param updated the updated to set
     */
    public void setUpdated( Date updated ) {
        this.updated = updated;
    }

    /**
     * @return the gitUrl
     */
    public String getGitUrl() {
        return gitUrl;
    }

    /**
     * @param gitUrl the gitUrl to set
     */
    public void setGitUrl( String gitUrl ) {
        this.gitUrl = gitUrl;
    }

    /**
     * @return the language
     */
    public String getLanguage() {
        return language;
    }

    /**
     * @param language the language to set
     */
    public void setLanguage( String language ) {
        this.language = language;
    }

    /**
     * @return the defaultBranch
     */
    public String getDefaultBranch() {
        return defaultBranch;
    }

    /**
     * @param defaultBranch the defaultBranch to set
     */
    public void setDefaultBranch( String defaultBranch ) {
        this.defaultBranch = defaultBranch;
    }

    /**
     * @return the owner
     */
    public Owner getOwner() {
        return owner;
    }

    /**
     * @param owner the owner to set
     */
    public void setOwner( Owner owner ) {
        this.owner = owner;
    }

    /* 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String
                .format(
                        "{Repository: {id:%s, name:%s, fullName:%s, restricted:%s, htmlUrl:%s, description:%s, created:%s, updated:%s, gitUrl:%s, language:%s, defaultBranch:%s, owner:%s}",
                        id, name, fullName, restricted, htmlUrl, description,
                        created, updated, gitUrl, language, defaultBranch,
                        owner );
    }
}

Второй шаг: реализовать синтаксический анализатор JSON с классом JsonParser


У нас есть представление JSON в наших классах Java (наша модель).
Теперь мы должны проанализировать ответ и создать экземпляры классов модели. Это работа нашего класса
ParseRepositoryJsonResponse. 

Конструктор синтаксического анализа получает ответ как
InputStream  (помните, что класс JsonParser является API с низким уровнем рычага, это обеспечивает нам лучшую производительность, чем класс JsonObject).

Метод
getRepositories ()  анализирует InputStream с JsonParser, создает объекты модели с данными JSON и возвращает список объектов Repository.

Важно знать, как работает анализатор, он обеспечивает прямой доступ только для чтения к данным JSON в потоковом режиме.
Это наиболее эффективный способ чтения данных JSON.

JsonParser анализирует JSON, используя модель программирования «парсинг по запросу».
В этой модели клиентский код управляет потоком и вызывает метод next () для перевода анализатора в следующее состояние после обработки каждого элемента. Анализатор может генерировать следующие события: START_OBJECT, END_OBJECT, START_ARRAY, END_ARRAY, KEY_NAME, VALUE_STRING, VALUE_NUMBER, VALUE_TRUE, VALUE_FALSE и VALUE_NULL.


Когда наш JSON анализируется, мы используем
Key Events,  чтобы определить, какое свойство мы хотим прочитать из потока.
ParseRepositoryJsonResponse class
/**
 * github-rest
 *
 * Copyright 2015 "GDL Java User Group"
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package mx.gdljug.githubrest.model.json;

import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;

import mx.gdljug.githubrest.model.pojo.Owner;
import mx.gdljug.githubrest.model.pojo.Repository;

/**
 * Parse the github rest service response and transform it 
 * in {@link mx.gdljug.githubrest.model.pojo.Repository} model
 *
 * @author juanitodread
 * @since 1.0
 *
 * Mar 28, 2015
 */
public class ParseRepositoryJsonResponse {

    private InputStream jsonResponse;
    
    private JsonParser jsonParser;
    
    private static final SimpleDateFormat ISO_8601_FORMATTER = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'" );
    
    
    /**
     * Instantiate a new ParseRepositoryJsonResponse
     * 
     * @param jsonResponse
     */
    public ParseRepositoryJsonResponse( InputStream jsonResponse ) {
        this.jsonResponse = jsonResponse;
    }

    /**
     * Parse the response of the REST service and return the content in 
     * a collection of Repositories.
     * @return List<Repository>
     */
    public List<Repository> getResositories( ) {
        jsonParser             = Json.createParser( jsonResponse );
        JsonParser.Event evt   = null;
        List<Repository> repos = new ArrayList<>( );
        Repository repo        = null;
        Owner owner            = null;
        
        while(jsonParser.hasNext( )){
            evt = jsonParser.next( );
            
          // First get repository objects
          if(Event.START_OBJECT == evt){    
                repo = new Repository( );
              while(jsonParser.hasNext( )) {
                  evt = jsonParser.next( );
                  if(Event.KEY_NAME != evt && Event.END_OBJECT != evt) {
                      continue;
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "id" )){
                      evt = jsonParser.next( );
                      repo.setId( jsonParser.getLong( ) );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "name" )){
                      evt = jsonParser.next( );                      
                      repo.setName( jsonParser.getString( ) );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "full_name" )){
                      evt = jsonParser.next( );
                      repo.setFullName( jsonParser.getString( ) );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "private" )){
                      evt = jsonParser.next( );
                      repo.setRestricted( Event.VALUE_TRUE == evt );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "html_url" )){
                      evt = jsonParser.next( );
                      repo.setHtmlUrl( jsonParser.getString( ) );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "description" )){
                      evt = jsonParser.next( );
                      repo.setDescription( jsonParser.getString( ) );
                  }
                  if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "created_at" )){
                      evt = jsonParser.next( );
                      try {
                        repo.setCreated( ISO_8601_FORMATTER.parse( jsonParser.getString( ) ) );
                    } catch ( ParseException e ) {
                        e.printStackTrace();
                    }
                  }
                  if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "updated_at" )){
                      evt = jsonParser.next( );
                      try {
                        repo.setUpdated( ISO_8601_FORMATTER.parse( jsonParser.getString( ) ) );
                    } catch ( ParseException e ) {
                        e.printStackTrace();
                    }
                  }
                  else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "git_url" )){
                      evt = jsonParser.next( );
                      repo.setGitUrl( jsonParser.getString( ) );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "language" )){
                      evt = jsonParser.next( );
                      repo.setLanguage( Event.VALUE_NULL != evt ? jsonParser.getString( ) : "" );
                  }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "default_branch" )){
                      evt = jsonParser.next( );
                      repo.setDefaultBranch( jsonParser.getString( ) );
                  }
                  
                  // Get owner objects
                  else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "owner" )) {
                      owner = new Owner( );
                      while(jsonParser.hasNext( )){
                          evt = jsonParser.next( );
                          if(Event.KEY_NAME != evt && Event.END_OBJECT != evt) {
                              continue;
                          } else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "login" )){
                              evt = jsonParser.next( );
                              owner.setUserName( jsonParser.getString( ) );
                          }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "html_url" )){
                              evt = jsonParser.next( );
                              owner.setHtmlUrl( jsonParser.getString( ) );
                          }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "type" )){
                              evt = jsonParser.next( );
                              owner.setType( jsonParser.getString( ) );
                          }else if(Event.KEY_NAME == evt && jsonParser.getString( ).matches( "site_admin" )){
                              evt = jsonParser.next( );
                              owner.setAdmin( Event.VALUE_TRUE == evt );
                          }else if(Event.END_OBJECT == evt ){
                              
                              repo.setOwner( owner );                             
                              break;
                          }
                      }
                  } else if ( Event.END_OBJECT == evt ) {
                      repos.add( repo );
                      break;
                  }
              }
              
          }
        }
        
        return repos;
    }
    
}

Третий шаг: использование службы JSON REST


Это последний шаг.
Нам нужно только использовать сервис и отправить JSON-ответ парсеру. После этого мы можем манипулировать JSON с нашими модельными классами.

В этом случае мы анализируем JSON и печатаем наши объекты модели в консоли.
Также у нас есть
фильтр  для печати репозиториев в соответствии со свойством «language» репозитория, например,
получение всех репозиториев Java от пользователя dzone.
Основной класс
/**
 * github-rest
 *
 * Copyright 2015 "GDL Java User Group"
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package mx.gdljug.githubrest;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;

import javax.ws.rs.NotFoundException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;

import mx.gdljug.githubrest.model.json.ParseRepositoryJsonResponse;
import mx.gdljug.githubrest.model.pojo.Repository;

/**
 * Consumes a rest service with all the repositories that a github user
 * has. Also you can filter your response according filters:
 * 
 *      Argument 2: Language filter - Filter a repository according the 
 *                  programming language of the repository.
 *
 * @author juanitodread
 * @since 1.0
 *
 * Mar 28, 2015
 */
public class Main {

    private static final String REST_GITHUB_URL = "https://api.github.com";
    
    private static final String USERS_RESOURCE = "/users/";
    
    private static final String USER_REPOS_RESOURCE = "/repos";
    
    /**
     * Start application
     * 
     * @param args A valid github user name
     * @throws IOException 
     */
    public static void main( String... args ) throws IOException {
        if ( args == null || args.length == 0 || args[0].isEmpty( ) ) {
            throw new IllegalArgumentException( "Invalid github user" );
        }
        
        // Read input arguments
        String githubUser = args[0];
        String language = args.length == 2 ? args[1]: null;
        String userReposResource = String.format( "%s%s%s", USERS_RESOURCE,
                githubUser, USER_REPOS_RESOURCE );
        
        // Invoke REST service
        Client restClient = ClientBuilder.newClient( );
        WebTarget githubRest = restClient.target( REST_GITHUB_URL ).path( userReposResource );
        
        InputStream response = null;
        try {
            response = githubRest.request( ).get( InputStream.class );
        } catch ( NotFoundException ex ) {
            System.out.println( "HTTP 404 Not Found: It seems that your github user does not exist." );
            System.exit( 1 );
        }
        
        // Parse response
        ParseRepositoryJsonResponse githubParserResponse = new ParseRepositoryJsonResponse( response );
        List<Repository> repos = githubParserResponse.getResositories( );

        // User wants filters?
        if ( language != null ) {
            repos = repos.stream( )
                    .filter( x -> x.getLanguage( ).equals( language ) )
                    .collect( Collectors.toList( ) );
        }
        
        // Print response
        repos.forEach( x -> {
            System.out.printf( "-----------------Repository %d------------------%n", x.getId( ) );
            System.out.printf( "| Name: %s%n", x.getName( ) );
            System.out.printf( "| Full name: %s%n", x.getFullName( ) );
            System.out.printf( "| Private: %b%n", x.isRestricted( ) );
            System.out.printf( "| HTML URL: %s%n", x.getHtmlUrl( ) );
            System.out.printf( "| Description: %s%n", x.getDescription( ) );
            System.out.printf( "| Name: %s%n", x.getName( ) );
            System.out.printf( "| Created: %tF %tT:%tL %n", x.getCreated( ), x.getCreated( ), x.getCreated( ) );
            System.out.printf( "| Updated: %tF %tT:%tL %n", x.getUpdated( ), x.getUpdated( ), x.getUpdated( ) );
            System.out.printf( "| Git URL: %s%n", x.getGitUrl( ) );
            System.out.printf( "| Languaje: %s%n", x.getLanguage( ) );
            System.out.printf( "| Default branch: %s%n", x.getDefaultBranch( ) );
            System.out.printf( "| Owner: %n" );
            System.out.printf( "| \tUser name: %s%n", x.getOwner( ).getUserName( ) );
            System.out.printf( "| \tHTML URL: %s%n", x.getOwner( ).getHtmlUrl( ) );
            System.out.printf( "| \tType: %s%n", x.getOwner( ).getType( ) );
            System.out.printf( "| \tAdministrator: %b%n", x.getOwner( ).isAdmin( ) );
            System.out.printf( "-----------------------------------------------------%n%n" );
        } );
    }

}

Весь код можно загрузить из
группы пользователей Java в Гвадалахаре. 
Чтобы запустить jar, вам просто нужно: java -jar github-rest_1.0.jar dzone