There is little-to-no official documentation for the different parts of this setup. So, I will do my best here to explain each of the steps. Feel free to skip to just the parts that you need.

My goal was to automate sending a auto-generated CSV file to Google’s Fusion Tables. The service account adds another obstacle for the automation, at least the three-way authentication with OAuth wouldn’t be involved. Here’s the obstacles that I’ve had to overcome for this particular project:

  1. Using REST or Google’s Java library for Fusiontables
  2. Authenticating the service account
  3. Creating new table with service account
  4. Viewing the created table with the owner account
  5. Inserting new row data from CSV
  6. Full combined code example

1. Using REST or Google’s Java library for Fusion Tables

Initially, I used REST to access the fusiontables API, and got as far as creating the new table before discovering Google’s library to potentially simplify the process and make the code look cleaner. Using HTTP requests for the API is possible, but Google’s Java library for their Fusion Tables works very well and I haven’t found myself limited yet.

The dependencies are easy to add with Gradle: compile 'com.google.apis:google-api-services-fusiontables:v2-rev4-1.20.0'

Also, if you are using the service account and would like to see the created tables with the owning account, then the permission will have to be added (explained more in part 4), so also add: compile 'com.google.apis:google-api-services-drive:v2-rev182-1.20.0'

2. Authenticating the service account

In the main Google Developers Console, first enable ‘Fusion Tables API’ in the ‘APIs’ section for your project. Then, in the ‘Credentials’ section, add service account and choose the ‘p12’ security key option. For the purposes of this walkthrough, I’ll assume it is in the project’s root directory. Also, keep track of the ‘email address’ for the service account because it will be needed again soon.

Adding the P12 authentication will be done in the GoogleCredential.Builder:

GoogleCredential credential = new GoogleCredential.Builder()
        ...
        .setServiceAccountPrivateKeyFromP12File(new File("my-service-worker-key.p12"))
        .build();

3. Creating new table with service account

This was the most straight-forward part:

// Must have isExportable set to true when using service account.
Table table = new Table().setName("my-table-name").setIsExportable(true);
List<Column> columns = new ArrayList<>();
columns.add(new Column().setName("aString").setType("STRING"));
columns.add(new Column().setName("aNumber").setType("NUMBER"));
columns.add(new Column().setName("2015-08-26").setType("DATETIME"));
table.setColumns(columns);
mFusionTable.table().insert(table).execute();

4. Viewing the created table with the owner account

At this time, the newly created table will only be visible to the service account. It will NOT be visible to anybody else, not even the account that created the service account. So, to get past this obstacle, we will have to add the further visibility/permissions using the Google Drive API.

Here’s a quick example for how to make the user owner account able to see the created fusion tables from the service account:

String tableId = mFusionTable.table().insert(table).execute().getTableId();
Permission permission = new Permission();
permission.setValue("my-owner-account@gmail.com");
permission.setType("user");
permission.setRole("owner");
mDrive.permissions().insert(tableId, permission).execute();

For more info on adding permissions, check out the Google Drive Permission Docs

5. Inserting new row data from CSV

Google’s Java library has an overloaded method for adding data from an arbitrary source: Table.importRows(String tableId, AbstractInputStreamContent).

After examining the hidden javadoc, I see that AbstractInputStreamContent has an extended child with FileContent(fileType, file). It works for CSV, but there is a catch. The file type can’t be declared as CSV because the the import process only accepts the file type of ‘application/octet-stream’.

Here’s how this part works:

// FIXME: Assuming sample data in project root and matches table schema.
File file = new File("my-sample-data.csv);
mFusionTable.table().importRows(tableId,
        new FileContent("application/octet-stream", file)).execute();

6. Full combined code example

(try-catches not included here for better readability. Same reason for hardcoded Strings.)

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.Permission;
import com.google.api.services.fusiontables.Fusiontables;
import com.google.api.services.fusiontables.FusiontablesScopes;
import com.google.api.services.fusiontables.model.Column;
import com.google.api.services.fusiontables.model.Table;

public class MyFusionTable {
    private static final String MY_APP_NAME = "My App Name";

    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static HttpTransport sHttpTransport;

    private Fusiontables mFusionTable;
    private Drive mDrive;

    static {
        sHttpTransport = GoogleNetHttpTransport.newTrustedTransport();
    }

    public static void main(String[] args) {
        // Sample usage
        MyFusionTable myFusionTable = new MyFusionTable();
        myFusionTable.createNewtable("my-table-name", "my-sample-date.csv");
    }

    public MyFusionTable() {
        GoogleCredential credential = getCredential();
        mFusionTable = new Fusiontables.Builder(sHttpTransport, JSON_FACTORY, credential)
                .setApplicationName(MY_APP_NAME).build();
        mDrive = new Drive.Builder(sHttpTransport, JSON_FACTORY, credential)
                .setApplicationName(MY_APP_NAME).build();
    }

    public String createNewTable(String tableName, String csvFilePath) {
        // Must have isExportable set to true when using service account.
        Table table = new Table().setName(tableName).setIsExportable(true);
        List<Column> columns = new ArrayList<>();
        // TODO: Update with real column names and types.
        columns.add(new Column().setName("aString").setType("STRING"));
        columns.add(new Column().setName("aNumber").setType("NUMBER"));
        columns.add(new Column().setName("2015-08-26").setType("DATETIME"));
        table.setColumns(columns);
        String tableId = mFusionTable.table().insert(table).execute().getTableId();

        mDrive.permissions().insert(tableId, getPermission()).execute();

        mFusionTable.table().importRows(tableId,
                new FileContent("application/octet-stream", new File(csvFilePath))).execute();

        return tableId;
    }

    // Just for debugging purposes.
    public String debugGetListOfTables() {
        return mFusionTable.table().list().execute().getItems().toString();
    }

    // Just for debugging purposes.
    public String debugGetTableDetails(String tableId) {
        return mFusionTable.table().get(tableId).execute().toPrettyString();
    }

    private Credential getCredential() {
        return new GoogleCredential.Builder()
              .setTransport(sHttpTransport)
              .setJsonFactory(JSON_FACTORY)
              .setServiceAccountId("MY-SERVICE-ACCOUNT-EMAIL@developer.gserviceaccount.com") // TODO: Add proper email.
              .setServiceAccountScopes(Arrays.asList(FusiontablesScopes.FUSTIONTABLES, DriveScopes.DRIVE))
              .setServiceAccountPrivateKeyFromP12File(new File("my-service-worker-key.p12")) // TODO: Add proper key
              .build();
    }

    private Permission getPermission() {
        Permission permission = new Permission();
        // TODO: Add proper owner email address.
        permission.setValue("my-owner-account@gmail.com");
        permission.setType("user");
        permission.setRole("owner");
        return permission;
    }
}

Congrats, you should now finally have some working code for automating the creation of new Fusion Tables.

Now a quick word from a tech company who helps support me and this site: