Google AppEngine - accessing Google Spreadsheet in Java
Here is sample Java code snippet to connect to a Google Spreadsheet document and read and modify data.
I used this code successfully somewhere in 2012.
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.google.gdata.client.spreadsheet.CellQuery;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.Cell;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
public class SpreadsheetExample {
private static final FeedURLFactory urlFactory = FeedURLFactory.getDefault();
private SpreadsheetService service;
// ==========================================================================
// CONNECT to Google Spreadsheet API
/** Opens a connection to Google spreadsheet API. */
public void connect() {
SpreadsheetService newService = new SpreadsheetService("application_name");
// Google account login and passwords to access your spreadsheet.
// Password is in plain text. For sure there are better ways to do that
// so the passwords does not have to be in the code, but the simplest.
String email = "user@example.com";
String password = "password";
try {
newService.setUserCredentials(email, password);
} catch (AuthenticationException e) {
throw new RuntimeException("Cannot authenticate, invalid user/password", e);
}
this.service = newService;
}
// ==========================================================================
// Load data
/**
* Loads data from the sheet.
* @returns List of all non empty values in the first sheet column as
* 'row_number:value', where row_number=1,2,...
*/
public List<String> loadExampleData() {
CellFeed cellFeed = getCellFeed();
List<String> result = new ArrayList<String>();
for (CellEntry entry : cellFeed.getEntries()) {
Cell cell = entry.getCell();
if (cell.getCol() == 1) {
String value = cell.getRow() + cell.getValue();
result.add(value);
}
}
return result;
}
// ==========================================================================
// Save data
/**
* Sets new cell value for column=1 in given row.
* @param row Row number, if the sheet does not have so many row, new empty
* rows will be added.
* @param value New cell value as a text
*/
public void setExampleValue(int row, String value) {
extendSheetIfTooShort(row);
CellFeed cellFeed = getCellFeedForUpdate(row, row, 1, 1);
updateCell(cellFeed.getEntries().get(0), value);
}
// ==========================================================================
// Access a worksheet in CELL mode
/**
* Returns CellFeed connected to predefined, existing spreadsheet and a
* sheet inside it.
* Provided CellFeed will include only non empty cells.
* This method is convenient for reading, but not always so good for updating
* (you do not see all cells).
*/
private CellFeed getCellFeed() {
try {
return service.getFeed(findWorksheet().getCellFeedUrl(), CellFeed.class);
} catch (ServiceException e) {
throw new RuntimeException("Service error when loading data", e);
} catch (IOException e) {
throw new RuntimeException("Connection with server broken", e);
}
}
/**
* Returns CellFeed for update connected to predefined, existing spreadsheet
* and a sheet inside it.
* Provided CellFeed will include all existing cells within given row and
* column range. Note that sheet can be smaller than specified ranges, then
* provided CellFeed will only include ranges up to the sheet size.
* This method is convenient for updating, but not always so good for reading
* (you can have a lot of empty cells).
* @param minRow Min row number (inclusive) - 1,2,...
* @param maxRow Max row number (inclusive) - 1,2,...
* @param minCol Min column number (inclusive) - 1,2,...
* @param maxCol Max column number (inclusive) - 1,2,...
*/
private CellFeed getCellFeedForUpdate(int minRow, int maxRow, int minCol, int maxCol) {
CellQuery cellQuery;
try {
cellQuery = new CellQuery(findWorksheet().getCellFeedUrl());
cellQuery.setMinimumCol(minCol);
cellQuery.setMaximumCol(maxCol);
cellQuery.setMinimumRow(minRow);
cellQuery.setMaximumRow(maxRow);
cellQuery.setReturnEmpty(true);
return service.query(cellQuery, CellFeed.class);
} catch (ServiceException e) {
throw new RuntimeException("Service error when getting data to edit", e);
} catch (IOException e) {
throw new RuntimeException("Connection with server broken", e);
}
}
private WorksheetEntry findWorksheet() throws IOException, ServiceException {
// Spreadsheet KEY is an unique identifier of a spreadsheet document.
// The KEY is part of spreadsheet document URL. To find it, just open the
// spreadsheet document in your browser and take the 'key' param value.
// For example:
// URL=https://docs.google.com/spreadsheet/ccc?key=0AuhY-asdcrtr123bc#gid=1
// => KEY=0AuhY-asdcrtr123bc
// (the real keys are usually much longer)
//
// Other approach to find spreadsheetKey could be to list all spreadsheets
// documents that belong the user and the select one by name. It would require
// more code and in particular one more call to API. Then it would stop working
// as soon as you name another spreadsheet documents with the same name.
// Thus, I think it is not worth the effort.
//
String spreadsheetKey = "0AuhY-asdcrtr123bc";
// Worksheet name is the name of a sheet inside the spreadsheet document.
// It is a name given by the user as seen in the spreadsheet. In particular
// it does not have to be unique, but this is the simplest way I found to
// identify a sheet.
// Note that this work only if your worksheet has unique name (within
// the spreadsheet document, not globally).
//
// Other approach to find a worksheet is to use worksheet position (1,2, ...)
// but I find it less convenient.
//
String worksheetName = "sheet1";
SpreadsheetFeed feed = service.getFeed(
urlFactory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
for (SpreadsheetEntry se : feed.getEntries()) {
if (se.getSpreadsheetLink().getHref().endsWith(spreadsheetKey)) {
for (WorksheetEntry we : se.getWorksheets()) {
if (we.getTitle().getPlainText().equalsIgnoreCase(worksheetName)) {
return we;
}
}
}
}
throw new RuntimeException("Cannot find worksheet=" + worksheetName);
}
/** Adds more rows to the sheet if it is too short. */
private void extendSheetIfTooShort(int minRows) {
try {
WorksheetEntry ws = findWorksheet();
if (ws.getRowCount() < minRows) {
ws.setRowCount(minRows);
ws.getRowCount();
ws.update();
}
} catch (ServiceException e) {
throw new RuntimeException("Service error when extending worksheet", e);
} catch (IOException e) {
throw new RuntimeException("Connection error when extending worksheet", e);
}
}
/** Updates cell value. */
private void updateCell(CellEntry entry, String newValue) {
entry.changeInputValueLocal(newValue);
try {
// Commit changes - send changes to Google spreadsheet API
entry.update();
} catch (ServiceException e) {
throw new RuntimeException("Service error when updating data", e);
} catch (IOException e) {
throw new RuntimeException("Connection error when updating data", e);
}
}
}