I already did a post giving an overview of interacting with Google Tasks using Ruby, but with the change in scope of my project, I now need to do the same in Java. Therefore, here is an overview of interacting with Google Tasks using Java. Do note that this probably won’t work on Android, it is meant to be used from Java Desktop editions.
Project Setup
Using gradle, the project setup is quite simple:
|
compile ( ['com.google.api-client:google-api-client:1.23.0'], ['com.google.apis:google-api-services-tasks:v1-rev49-1.23.0'], ['com.google.oauth-client:google-oauth-client-jetty:1.23.0'], ) |
Google API Setup
In order to access Google Tasks using Java, you will need to use Google’s OAuth. Google’s OAuth uses what they call client secrets file. These files contain all the information needed to access the selected services.
To get a client secrets file, you can follow my other post.
Handling the user’s credentials
This project is my first Java project since a long time ago. I quickly remembered how painful it can be to play with the interface/abstract class hell. You have to instantiate 20 different things before calling anything and selecting the right implementation, or even simply finding an implementation, is sometimes tricky. Here, I selected the following implementations:
- JsonFactory: com.google.api.client.json.jackson2.JacksonFactory, it was there and worked, so I used it;
- HttpTransport: com.google.api.client.http.javanet.NetHttpTransport, according to the API’s documentation “NetHttpTransport is based on the HttpURLConnection built into the Java SDK, so it is normally the preferred choice“;
- DataStoreFactory: com.google.api.client.util.store.FileDataStoreFactory, this implementation will store the tokens in a file (Ok … multiple files …). In my case, it will be in a directory called tokens in the current working directory;
Here is the authentication code I used. It will take care of caching the tokens, opening the browser if a new token is needed and getting the result token.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public class App { private JsonFactory jsonFactory; private HttpTransport transport; private Credential credentials; public App() { this.jsonFactory = new JacksonFactory(); this.transport = new NetHttpTransport(); this.credentials = null; } public void authorize() throws Exception { // Setup Datastore DataStoreFactory datastore = new FileDataStoreFactory( new File("tokens") ); // Load Client Secrets GoogleClientSecrets clientSecrets = GoogleClientSecrets.load( this.jsonFactory, new FileReader("client_secrets.json") ); // Set Up authorization code flow GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( this.transport, this.jsonFactory, clientSecrets, Collections.singleton(TasksScopes.TASKS) ).setDataStoreFactory(datastore).build(); // Authorize this.credentials = new AuthorizationCodeInstalledApp( flow, new LocalServerReceiver() ).authorize("user"); } } |
Initializing the Google Tasks API
In order to use the Google Tasks API, you need to build the service. Doing so requires most of the things that were initialized in the previous section:
|
public class App { public Tasks getTasksService() { return new Tasks.Builder( this.transport, this.jsonFactory, this.credentials ).build(); } } |
Interacting with Google Tasks using Java
Creating a task list
Once you have all the boilerplate done for the initialization of the API and the service, creating a tasklist becomes quite easy:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); tasklist = service.tasklists().insert( new TaskList().setTitle("generated") ).execute(); |
Finding a task list
The Google Tasks API only allows you to search by tasklist ID, not a title. This ID is automatically generated and therefore not really easy to use. The easiest way to find a task list is to list all task lists and find the one you are looking for in there:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); TaskList tasklist = tasklists.getItems().stream() .filter(t -> t.getTitle().equals("generated")) .findFirst() .orElse(null); |
Creating a task
In order to create a task, you first need a tasklist. Once you got that, creating the task is easy enough:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); TaskList tasklist = ... Task task = service.tasks().insert( tasklist.getId(), new Task().setTitle("generated") ).execute(); |
Finding a task
Just like finding a tasklist, you can’t directly search by task title. Therefore, you need to go iterate over the full list to find the one you are looking for:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); TaskList tasklist = ... Tasks tasks = service.tasks().list(tasklist.getId()).execute(); Task task = tasks.getItems().stream() .filter(t -> t.getTitle().equals("generated")) .findFirst() .orElse(null); |
Updating a task
Once you have a task (and a tasklist) in your hands, updating most of its fields can be done directly on the Task instance. The following example updates the due date of a task:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); TaskList tasklist = ... Task task = ... task.setDue(new DateTime(new Date(2020, 2, 3))); task = service.tasks().update( tasklist.getId(), task.getId(), task ).execute(); |
Completing a task
Just like updating a task, completing it is quite easy: set its status field to completed:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); TaskList tasklist = ... Task task = ... task.setStatus("completed"); task = service.tasks().update( tasklist.getId(), task.getId(), task ).execute(); |
Handling a large number of return values
Like any good online service, Google Tasks API handles a large number of values using pagination. By default, most APIs will return a maximum of 100 results. You are allowed to change this value, but in order to get good performance, you should not put it bigger.
Basically, the way to handle pagination is: do your normal call, check if you got a page token and if you do you know there are more results waiting. You can then call the API again with the page token in order to get the next result set:
|
App app = new App(); app.authorize(); com.google.api.services.tasks.Tasks service = app.getTasksService(); TaskList tasklist = ... Tasks tasks = null; String token = null; do { tasks = service.tasks().list(tasklist.getId()).setMaxResults(10l).setPageToken(token).execute(); System.out.println("Found " + tasks.getItems().size() + " tasks"); token = tasks.getNextPageToken(); } while (token != null); |
Sources