diff --git a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/Acl.java b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/Acl.java
new file mode 100644
index 000000000000..610f818e6cb9
--- /dev/null
+++ b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/Acl.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.services.bigquery.model.Dataset.Access;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Access Control for a BigQuery Dataset. BigQuery uses ACLs to manage permissions on datasets. ACLs
+ * are not directly supported on tables. A table inherits its ACL from the dataset that contains it.
+ * Project roles affect your ability to run jobs or manage the project, while dataset roles affect
+ * how you can access or modify the data inside of a project.
+ *
+ * @see Access Control
+ */
+public final class Acl implements Serializable {
+
+ private static final long serialVersionUID = 8357269726277191556L;
+
+ private final Entity entity;
+ private final Role role;
+
+ /**
+ * Dataset roles supported by BigQuery.
+ *
+ * @see Dataset Roles
+ */
+ public enum Role {
+ /**
+ * Can read, query, copy or export tables in the dataset.
+ */
+ READER,
+ /**
+ * Same as {@link #READER} plus can edit or append data in the dataset.
+ */
+ WRITER,
+ /**
+ * Same as {@link #WRITER} plus can update and delete the dataset.
+ */
+ OWNER
+ }
+
+ /**
+ * Base class for BigQuery entities that can be grant access to the dataset.
+ */
+ public static abstract class Entity implements Serializable {
+
+ private static final long serialVersionUID = 8111776788607959944L;
+
+ private final Type type;
+
+ /**
+ * Types of BigQuery entities.
+ */
+ public enum Type {
+ DOMAIN, GROUP, USER, VIEW
+ }
+
+ Entity(Type type) {
+ this.type = type;
+ }
+
+ public Type type() {
+ return type;
+ }
+
+ abstract Access toPb();
+
+ static Entity fromPb(Access access) {
+ if (access.getDomain() != null) {
+ return new Domain(access.getDomain());
+ }
+ if (access.getGroupByEmail() != null) {
+ return new Group(access.getGroupByEmail());
+ }
+ if (access.getSpecialGroup() != null) {
+ return new Group(access.getSpecialGroup());
+ }
+ if (access.getUserByEmail() != null) {
+ return new User(access.getUserByEmail());
+ }
+ if (access.getView() != null) {
+ return new View(TableId.fromPb(access.getView()));
+ }
+ // Unreachable
+ throw new BigQueryException(BigQueryException.UNKNOWN_CODE,
+ "Unrecognized access configuration", false);
+ }
+ }
+
+ /**
+ * Class for a BigQuery Domain entity. Objects of this class represent a domain to grant access
+ * to. Any users signed in with the domain specified will be granted the specified access.
+ */
+ public static final class Domain extends Entity {
+
+ private static final long serialVersionUID = -3033025857280447253L;
+
+ private final String domain;
+
+ /**
+ * Creates a Domain entity given the domain name.
+ */
+ public Domain(String domain) {
+ super(Type.DOMAIN);
+ this.domain = domain;
+ }
+
+ /**
+ * Returns the domain name.
+ */
+ public String domain() {
+ return domain;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Domain domainEntity = (Domain) o;
+ return Objects.equals(type(), domainEntity.type())
+ && Objects.equals(domain, domainEntity.domain());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type(), domain);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ @Override
+ Access toPb() {
+ return new Access().setDomain(domain);
+ }
+ }
+
+ /**
+ * Class for a BigQuery Group entity. Objects of this class represent a group to grante access to.
+ * A Group entity can be created given the group's email or can be a special group:
+ * {@link #ofProjectOwners()}, {@link #ofProjectReaders()}, {@link #ofProjectWriters()} or
+ * {@link #ofAllAuthenticatedUsers()}.
+ */
+ public static final class Group extends Entity {
+
+ private static final String PROJECT_OWNERS = "projectOwners";
+ private static final String PROJECT_READERS = "projectReaders";
+ private static final String PROJECT_WRITERS = "projectWriters";
+ private static final String ALL_AUTHENTICATED_USERS = "allAuthenticatedUsers";
+ private static final long serialVersionUID = 5146829352398103029L;
+
+ private final String identifier;
+
+ /**
+ * Creates a Group entity given its identifier. Identifier can be either a
+ *
+ * special group identifier or a group email.
+ */
+ public Group(String identifier) {
+ super(Type.GROUP);
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns group's identifier, can be either a
+ *
+ * special group identifier or a group email.
+ */
+ public String identifier() {
+ return identifier;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Group group = (Group) o;
+ return Objects.equals(type(), group.type()) && Objects.equals(identifier, group.identifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type(), identifier);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ @Override
+ Access toPb() {
+ switch (identifier) {
+ case PROJECT_OWNERS:
+ return new Access().setSpecialGroup(PROJECT_OWNERS);
+ case PROJECT_READERS:
+ return new Access().setSpecialGroup(PROJECT_READERS);
+ case PROJECT_WRITERS:
+ return new Access().setSpecialGroup(PROJECT_WRITERS);
+ case ALL_AUTHENTICATED_USERS:
+ return new Access().setSpecialGroup(ALL_AUTHENTICATED_USERS);
+ default:
+ return new Access().setGroupByEmail(identifier);
+ }
+ }
+
+ /**
+ * Returns a Group entity representing all project's owners.
+ */
+ public static Group ofProjectOwners() {
+ return new Group(PROJECT_OWNERS);
+ }
+
+ /**
+ * Returns a Group entity representing all project's readers.
+ */
+ public static Group ofProjectReaders() {
+ return new Group(PROJECT_READERS);
+ }
+
+ /**
+ * Returns a Group entity representing all project's writers.
+ */
+ public static Group ofProjectWriters() {
+ return new Group(PROJECT_WRITERS);
+ }
+
+ /**
+ * Returns a Group entity representing all BigQuery authenticated users.
+ */
+ public static Group ofAllAuthenticatedUsers() {
+ return new Group(ALL_AUTHENTICATED_USERS);
+ }
+ }
+
+ /**
+ * Class for a BigQuery User entity. Objects of this class represent a user to grant access to
+ * given the email address.
+ */
+ public static final class User extends Entity {
+
+ private static final long serialVersionUID = -4942821351073996141L;
+
+ private final String email;
+
+ /**
+ * Creates a User entity given the user's email.
+ */
+ public User(String email) {
+ super(Type.USER);
+ this.email = email;
+ }
+
+ /**
+ * Returns user's email.
+ */
+ public String email() {
+ return email;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ User user = (User) o;
+ return Objects.equals(type(), user.type()) && Objects.equals(email, user.email);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type(), email);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ @Override
+ Access toPb() {
+ return new Access().setUserByEmail(email);
+ }
+ }
+
+ /**
+ * Class for a BigQuery View entity. Objects of this class represent a view from a different
+ * dataset to grant access to. Queries executed against that view will have read access to tables
+ * in this dataset. The role field is not required when this field is set. If that view is updated
+ * by any user, access to the view needs to be granted again via an update operation.
+ */
+ public static final class View extends Entity {
+
+ private final TableId id;
+
+ /**
+ * Creates a View entity given the view's id.
+ */
+ public View(TableId id) {
+ super(Type.VIEW);
+ this.id = id;
+ }
+
+ /**
+ * Returns table's identity.
+ */
+ public TableId id() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ View view = (View) o;
+ return Objects.equals(type(), view.type()) && Objects.equals(id, view.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type(), id);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ @Override
+ Access toPb() {
+ return new Access().setView(id.toPb());
+ }
+ }
+
+ /**
+ * Build an ACL for an {@code entity} and a {@code role}.
+ */
+ public Acl(Entity entity, Role role) {
+ this.entity = checkNotNull(entity);
+ this.role = role;
+ }
+
+ /**
+ * Build an ACL for a view entity.
+ */
+ public Acl(View view) {
+ this.entity = checkNotNull(view);
+ this.role = null;
+ }
+
+ /**
+ * Returns the entity for this ACL.
+ */
+ public Entity entity() {
+ return entity;
+ }
+
+ /**
+ * Returns the role specified by this ACL.
+ */
+ public Role role() {
+ return role;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(entity, role);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Acl other = (Acl) obj;
+ return Objects.equals(this.entity, other.entity)
+ && Objects.equals(this.role, other.role);
+ }
+
+ Access toPb() {
+ Access accessPb = entity.toPb();
+ if (role != null) {
+ accessPb.setRole(role.name());
+ }
+ return accessPb;
+ }
+
+ static Acl fromPb(Access access) {
+ return new Acl(Entity.fromPb(access),
+ access.getRole() != null ? Role.valueOf(access.getRole()) : null);
+ }
+}
diff --git a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/DatasetId.java b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/DatasetId.java
new file mode 100644
index 000000000000..b0da5603d929
--- /dev/null
+++ b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/DatasetId.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.services.bigquery.model.DatasetReference;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Google BigQuery Dataset identity.
+ */
+public class DatasetId implements Serializable {
+
+ private static final long serialVersionUID = -6186254820908152300L;
+
+ private final String project;
+ private final String dataset;
+
+ /**
+ * Returns project's user-defined id
+ */
+ public String project() {
+ return project;
+ }
+
+ /**
+ * Returns dataset's user-defined id.
+ */
+ public String dataset() {
+ return dataset;
+ }
+
+ private DatasetId(String project, String dataset) {
+ this.project = project;
+ this.dataset = dataset;
+ }
+
+ /**
+ * Creates a dataset identity given project's and dataset's user-defined ids.
+ */
+ public static DatasetId of(String project, String dataset) {
+ return new DatasetId(checkNotNull(project), checkNotNull(dataset));
+ }
+
+ /**
+ * Creates a dataset identity given only its user-defined id.
+ */
+ public static DatasetId of(String dataset) {
+ return new DatasetId(null, checkNotNull(dataset));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof DatasetId && Objects.equals(toPb(), ((DatasetId) obj).toPb());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(project, dataset);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ public DatasetReference toPb() {
+ return new DatasetReference().setProjectId(project).setDatasetId(dataset);
+ }
+
+ public static DatasetId fromPb(DatasetReference datasetRef) {
+ return new DatasetId(
+ datasetRef.getProjectId(),
+ datasetRef.getDatasetId());
+ }
+}
diff --git a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/DatasetInfo.java b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/DatasetInfo.java
new file mode 100644
index 000000000000..773c314f8060
--- /dev/null
+++ b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/DatasetInfo.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.client.util.Data;
+import com.google.api.services.bigquery.model.Dataset;
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Google BigQuery Dataset information. A dataset is a grouping mechanism that holds zero or more
+ * tables. Datasets are the lowest level unit of access control; you cannot control access at the
+ * table level.
+ *
+ * @see
+ * Managing Jobs, Datasets, and Projects
+ */
+public final class DatasetInfo implements Serializable {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public DatasetInfo apply(Dataset pb) {
+ return DatasetInfo.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public Dataset apply(DatasetInfo datasetInfo) {
+ return datasetInfo.toPb();
+ }
+ };
+
+ private static final long serialVersionUID = -6615133444520365839L;
+
+ private final DatasetId datasetId;
+ private final List acl;
+ private final Long creationTime;
+ private final Long defaultTableLifetime;
+ private final String description;
+ private final String etag;
+ private final String friendlyName;
+ private final String id;
+ private final Long lastModified;
+ private final String location;
+ private final String selfLink;
+
+ public static final class Builder {
+
+ private DatasetId datasetId;
+ private List acl;
+ private Long creationTime;
+ private Long defaultTableLifetime;
+ private String description;
+ private String etag;
+ private String friendlyName;
+ private String id;
+ private Long lastModified;
+ private String location;
+ private String selfLink;
+
+ private Builder() {}
+
+ private Builder(DatasetInfo datasetInfo) {
+ this.datasetId = datasetInfo.datasetId;
+ this.acl = datasetInfo.acl;
+ this.creationTime = datasetInfo.creationTime;
+ this.defaultTableLifetime = datasetInfo.defaultTableLifetime;
+ this.description = datasetInfo.description;
+ this.etag = datasetInfo.etag;
+ this.friendlyName = datasetInfo.friendlyName;
+ this.id = datasetInfo.id;
+ this.lastModified = datasetInfo.lastModified;
+ this.location = datasetInfo.location;
+ this.selfLink = datasetInfo.selfLink;
+ }
+
+ /**
+ * Sets the dataset identity.
+ */
+ public Builder datasetId(DatasetId datasetId) {
+ this.datasetId = checkNotNull(datasetId);
+ return this;
+ }
+
+ /**
+ * Sets the dataset's access control configuration.
+ *
+ * @see Access Control
+ */
+ public Builder acl(List acl) {
+ this.acl = acl != null ? ImmutableList.copyOf(acl) : null;
+ return this;
+ }
+
+ Builder creationTime(Long creationTime) {
+ this.creationTime = creationTime;
+ return this;
+ }
+
+ /**
+ * Sets the default lifetime of all tables in the dataset, in milliseconds. The minimum value is
+ * 3600000 milliseconds (one hour). Once this property is set, all newly-created tables in the
+ * dataset will have an expirationTime property set to the creation time plus the value in this
+ * property, and changing the value will only affect new tables, not existing ones. When the
+ * expirationTime for a given table is reached, that table will be deleted automatically. If a
+ * table's expirationTime is modified or removed before the table expires, or if you provide an
+ * explicit expirationTime when creating a table, that value takes precedence over the default
+ * expiration time indicated by this property. This property is experimental and might be
+ * subject to change or removed.
+ */
+ public Builder defaultTableLifetime(Long defaultTableLifetime) {
+ this.defaultTableLifetime =
+ firstNonNull(defaultTableLifetime, Data.nullOf(Long.class));
+ return this;
+ }
+
+ /**
+ * Sets a user-friendly description for the dataset.
+ */
+ public Builder description(String description) {
+ this.description = firstNonNull(description, Data.nullOf(String.class));
+ return this;
+ }
+
+ Builder etag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+
+ /**
+ * Sets a user-friendly name for the dataset.
+ */
+ public Builder friendlyName(String friendlyName) {
+ this.friendlyName = firstNonNull(friendlyName, Data.nullOf(String.class));
+ return this;
+ }
+
+ Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ Builder lastModified(Long lastModified) {
+ this.lastModified = lastModified;
+ return this;
+ }
+
+ /**
+ * Sets the geographic location where the dataset should reside. This property is experimental
+ * and might be subject to change or removed.
+ *
+ * @see Dataset
+ * Location
+ */
+ public Builder location(String location) {
+ this.location = firstNonNull(location, Data.nullOf(String.class));
+ return this;
+ }
+
+ Builder selfLink(String selfLink) {
+ this.selfLink = selfLink;
+ return this;
+ }
+
+ /**
+ * Creates a {@code DatasetInfo} object.
+ */
+ public DatasetInfo build() {
+ return new DatasetInfo(this);
+ }
+ }
+
+ private DatasetInfo(Builder builder) {
+ datasetId = checkNotNull(builder.datasetId);
+ acl = builder.acl;
+ creationTime = builder.creationTime;
+ defaultTableLifetime = builder.defaultTableLifetime;
+ description = builder.description;
+ etag = builder.etag;
+ friendlyName = builder.friendlyName;
+ id = builder.id;
+ lastModified = builder.lastModified;
+ location = builder.location;
+ selfLink = builder.selfLink;
+ }
+
+ /**
+ * Returns the dataset identity.
+ */
+ public DatasetId datasetId() {
+ return datasetId;
+ }
+
+ /**
+ * Returns the dataset's access control configuration.
+ *
+ * @see Access Control
+ */
+ public List acl() {
+ return acl;
+ }
+
+ /**
+ * Returns the time when this dataset was created, in milliseconds since the epoch.
+ */
+ public Long creationTime() {
+ return creationTime;
+ }
+
+ /**
+ * Returns the default lifetime of all tables in the dataset, in milliseconds. Once this property
+ * is set, all newly-created tables in the dataset will have an expirationTime property set to the
+ * creation time plus the value in this property, and changing the value will only affect new
+ * tables, not existing ones. When the expirationTime for a given table is reached, that table
+ * will be deleted automatically. If a table's expirationTime is modified or removed before the
+ * table expires, or if you provide an explicit expirationTime when creating a table, that value
+ * takes precedence over the default expiration time indicated by this property.
+ */
+ public Long defaultTableLifetime() {
+ return defaultTableLifetime;
+ }
+
+ /**
+ * Returns a user-friendly description for the dataset.
+ */
+ public String description() {
+ return description;
+ }
+
+ /**
+ * Returns the hash of the dataset resource.
+ */
+ public String etag() {
+ return etag;
+ }
+
+ /**
+ * Returns a user-friendly name for the dataset.
+ */
+ public String friendlyName() {
+ return friendlyName;
+ }
+
+ /**
+ * Returns an opaque id for the dataset.
+ */
+ public String id() {
+ return id;
+ }
+
+ /**
+ * Returns the time when this dataset or any of its tables was last modified, in milliseconds
+ * since the epoch.
+ */
+ public Long lastModified() {
+ return lastModified;
+ }
+
+ /**
+ * Returns the geographic location where the dataset should reside.
+ *
+ * @see
+ * Dataset Location
+ */
+ public String location() {
+ return location;
+ }
+
+ /**
+ * Returns an URL that can be used to access the resource again. The returned URL can be used for
+ * get or update requests.
+ */
+ public String selfLink() {
+ return selfLink;
+ }
+
+ /**
+ * Returns a builder for the {@code DatasetInfo} object.
+ */
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("datasetId", datasetId)
+ .add("creationTime", creationTime)
+ .add("defaultTableLifetime", defaultTableLifetime)
+ .add("description", description)
+ .add("etag", etag)
+ .add("friendlyName", friendlyName)
+ .add("id", id)
+ .add("lastModified", lastModified)
+ .add("location", location)
+ .add("selfLink", selfLink)
+ .add("acl", acl)
+ .toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(datasetId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof DatasetInfo && Objects.equals(toPb(), ((DatasetInfo) obj).toPb());
+ }
+
+ Dataset toPb() {
+ Dataset datasetPb = new Dataset();
+ datasetPb.setDatasetReference(datasetId.toPb());
+ datasetPb.setCreationTime(creationTime);
+ datasetPb.setDefaultTableExpirationMs(defaultTableLifetime);
+ datasetPb.setDescription(description);
+ datasetPb.setEtag(etag);
+ datasetPb.setFriendlyName(friendlyName);
+ datasetPb.setId(id);
+ datasetPb.setLastModifiedTime(lastModified);
+ datasetPb.setLocation(location);
+ datasetPb.setSelfLink(selfLink);
+ if (acl != null) {
+ datasetPb.setAccess(Lists.transform(acl, new Function() {
+ @Override
+ public Dataset.Access apply(Acl acl) {
+ return acl.toPb();
+ }
+ }));
+ }
+ return datasetPb;
+ }
+
+ /**
+ * Returns a builder for the DatasetInfo object given it's user-defined id.
+ */
+ public static Builder builder(String datasetId) {
+ return new Builder().datasetId(DatasetId.of(datasetId));
+ }
+
+ /**
+ * Returns a builder for the DatasetInfo object given it's project and user-defined id.
+ */
+ public static Builder builder(String projectId, String datasetId) {
+ return new Builder().datasetId(DatasetId.of(projectId, datasetId));
+ }
+
+ /**
+ * Returns a builder for the DatasetInfo object given it's identity.
+ */
+ public static Builder builder(DatasetId datasetId) {
+ return new Builder().datasetId(datasetId);
+ }
+
+ static DatasetInfo fromPb(Dataset datasetPb) {
+ Builder builder = builder(datasetPb.getDatasetReference().getProjectId(),
+ datasetPb.getDatasetReference().getDatasetId());
+ if (datasetPb.getAccess() != null) {
+ builder.acl(Lists.transform(datasetPb.getAccess(),
+ new Function() {
+ @Override
+ public Acl apply(Dataset.Access f) {
+ return Acl.fromPb(f);
+ }
+ }));
+ }
+ if (datasetPb.getCreationTime() != null) {
+ builder.creationTime(datasetPb.getCreationTime());
+ }
+ if (datasetPb.getDefaultTableExpirationMs() != null) {
+ builder.defaultTableLifetime(datasetPb.getDefaultTableExpirationMs());
+ }
+ if (datasetPb.getDescription() != null) {
+ builder.description(datasetPb.getDescription());
+ }
+ if (datasetPb.getEtag() != null) {
+ builder.etag(datasetPb.getEtag());
+ }
+ if (datasetPb.getFriendlyName() != null) {
+ builder.friendlyName(datasetPb.getFriendlyName());
+ }
+ if (datasetPb.getId() != null) {
+ builder.id(datasetPb.getId());
+ }
+ if (datasetPb.getLastModifiedTime() != null) {
+ builder.lastModified(datasetPb.getLastModifiedTime());
+ }
+ if (datasetPb.getLocation() != null) {
+ builder.location(datasetPb.getLocation());
+ }
+ if (datasetPb.getSelfLink() != null) {
+ builder.selfLink(datasetPb.getSelfLink());
+ }
+ return builder.build();
+ }
+}
diff --git a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/TableId.java b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/TableId.java
new file mode 100644
index 000000000000..6747dbf9923f
--- /dev/null
+++ b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/TableId.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.services.bigquery.model.TableReference;
+import com.google.common.base.Function;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Google BigQuery Table identity.
+ */
+public class TableId implements Serializable {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public TableId apply(TableReference pb) {
+ return TableId.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public TableReference apply(TableId tableId) {
+ return tableId.toPb();
+ }
+ };
+ private static final long serialVersionUID = -6186254820908152300L;
+
+ private final String project;
+ private final String dataset;
+ private final String table;
+
+ /**
+ * Returns project's user-defined id
+ */
+ public String project() {
+ return project;
+ }
+
+ /**
+ * Returns dataset's user-defined id.
+ */
+ public String dataset() {
+ return dataset;
+ }
+
+ /**
+ * Returns table's user-defined id.
+ */
+ public String table() {
+ return table;
+ }
+
+ private TableId(String project, String dataset, String table) {
+ this.project = project;
+ this.dataset = dataset;
+ this.table = table;
+ }
+
+ /**
+ * Creates a table identity given project's, dataset's and table's user-defined ids.
+ */
+ public static TableId of(String project, String dataset, String table) {
+ return new TableId(checkNotNull(project), checkNotNull(dataset), checkNotNull(table));
+ }
+
+ /**
+ * Creates a table identity given dataset's and table's user-defined ids.
+ */
+ public static TableId of(String dataset, String table) {
+ return new TableId(null, checkNotNull(dataset), checkNotNull(table));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof TableId && Objects.equals(toPb(), ((TableId) obj).toPb());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(project, dataset, table);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ TableReference toPb() {
+ return new TableReference().setProjectId(project).setDatasetId(dataset).setTableId(table);
+ }
+
+ static TableId fromPb(TableReference tableRef) {
+ return new TableId(
+ tableRef.getProjectId(),
+ tableRef.getDatasetId(),
+ tableRef.getTableId());
+ }
+}
diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/AclTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/AclTest.java
new file mode 100644
index 000000000000..52159b0665ac
--- /dev/null
+++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/AclTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.api.services.bigquery.model.Dataset;
+import com.google.gcloud.bigquery.Acl.Domain;
+import com.google.gcloud.bigquery.Acl.Entity;
+import com.google.gcloud.bigquery.Acl.Entity.Type;
+import com.google.gcloud.bigquery.Acl.Group;
+import com.google.gcloud.bigquery.Acl.Role;
+import com.google.gcloud.bigquery.Acl.User;
+import com.google.gcloud.bigquery.Acl.View;
+
+import org.junit.Test;
+
+public class AclTest {
+
+ @Test
+ public void testDomainEntity() {
+ Domain entity = new Domain("d1");
+ assertEquals("d1", entity.domain());
+ assertEquals(Type.DOMAIN, entity.type());
+ Dataset.Access pb = entity.toPb();
+ assertEquals(entity, Entity.fromPb(pb));
+ }
+
+ @Test
+ public void testGroupEntity() {
+ Group entity = new Group("g1");
+ assertEquals("g1", entity.identifier());
+ assertEquals(Type.GROUP, entity.type());
+ Dataset.Access pb = entity.toPb();
+ assertEquals(entity, Entity.fromPb(pb));
+ }
+
+ @Test
+ public void testSpecialGroupEntity() {
+ Group entity = Group.ofAllAuthenticatedUsers();
+ assertEquals("allAuthenticatedUsers", entity.identifier());
+ entity = Group.ofProjectWriters();
+ assertEquals("projectWriters", entity.identifier());
+ entity = Group.ofProjectReaders();
+ assertEquals("projectReaders", entity.identifier());
+ entity = Group.ofProjectOwners();
+ assertEquals("projectOwners", entity.identifier());
+ }
+
+ @Test
+ public void testUserEntity() {
+ User entity = new User("u1");
+ assertEquals("u1", entity.email());
+ assertEquals(Type.USER, entity.type());
+ Dataset.Access pb = entity.toPb();
+ assertEquals(entity, Entity.fromPb(pb));
+ }
+
+ @Test
+ public void testViewEntity() {
+ TableId viewId = TableId.of("project", "dataset", "view");
+ View entity = new View(viewId);
+ assertEquals(viewId, entity.id());
+ assertEquals(Type.VIEW, entity.type());
+ Dataset.Access pb = entity.toPb();
+ assertEquals(entity, Entity.fromPb(pb));
+ }
+
+ @Test
+ public void testAcl() {
+ Acl acl = new Acl(Group.ofAllAuthenticatedUsers(), Role.READER);
+ assertEquals(Group.ofAllAuthenticatedUsers(), acl.entity());
+ assertEquals(Role.READER, acl.role());
+ Dataset.Access pb = acl.toPb();
+ assertEquals(acl, Acl.fromPb(pb));
+ View view = new View(TableId.of("project", "dataset", "view"));
+ acl = new Acl(view);
+ assertEquals(view, acl.entity());
+ assertEquals(null, acl.role());
+ }
+}
diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/DatasetIdTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/DatasetIdTest.java
new file mode 100644
index 000000000000..0af665895d71
--- /dev/null
+++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/DatasetIdTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class DatasetIdTest {
+
+ private static final DatasetId DATASET = DatasetId.of("dataset");
+ private static final DatasetId DATASET_COMPLETE = DatasetId.of("project", "dataset");
+
+ @Test
+ public void testOf() {
+ assertEquals(null, DATASET.project());
+ assertEquals("dataset", DATASET.dataset());
+ assertEquals("project", DATASET_COMPLETE.project());
+ assertEquals("dataset", DATASET_COMPLETE.dataset());
+ }
+
+ @Test
+ public void testEquals() {
+ compareDatasetIds(DATASET, DatasetId.of("dataset"));
+ compareDatasetIds(DATASET_COMPLETE, DatasetId.of("project", "dataset"));
+ }
+
+ @Test
+ public void testToPbAndFromPb() {
+ compareDatasetIds(DATASET, DatasetId.fromPb(DATASET.toPb()));
+ compareDatasetIds(DATASET_COMPLETE, DatasetId.fromPb(DATASET_COMPLETE.toPb()));
+ }
+
+ private void compareDatasetIds(DatasetId expected, DatasetId value) {
+ assertEquals(expected, value);
+ assertEquals(expected.project(), value.project());
+ assertEquals(expected.dataset(), value.dataset());
+ assertEquals(expected.hashCode(), value.hashCode());
+ }
+}
diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/DatasetInfoTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/DatasetInfoTest.java
new file mode 100644
index 000000000000..43c80f6afe83
--- /dev/null
+++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/DatasetInfoTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class DatasetInfoTest {
+
+ private static final List ACCESS_RULES = ImmutableList.of(
+ new Acl(Acl.Group.ofAllAuthenticatedUsers(), Acl.Role.READER),
+ new Acl(new Acl.View(TableId.of("project", "dataset", "table")), Acl.Role.WRITER));
+ private static final Long CREATION_TIME = System.currentTimeMillis();
+ private static final Long DEFAULT_TABLE_EXPIRATION = CREATION_TIME + 100;
+ private static final String DESCRIPTION = "description";
+ private static final String ETAG = "0xFF00";
+ private static final String FRIENDLY_NAME = "friendlyDataset";
+ private static final String ID = "P/D:1";
+ private static final Long LAST_MODIFIED = CREATION_TIME + 50;
+ private static final String LOCATION = "";
+ private static final String SELF_LINK = "http://bigquery/p/d";
+ private static final DatasetId DATASET_ID = DatasetId.of("dataset");
+ private static final DatasetId DATASET_ID_COMPLETE = DatasetId.of("project", "dataset");
+ private static final DatasetInfo DATASET_INFO = DatasetInfo.builder(DATASET_ID)
+ .acl(ACCESS_RULES)
+ .creationTime(CREATION_TIME)
+ .defaultTableLifetime(DEFAULT_TABLE_EXPIRATION)
+ .description(DESCRIPTION)
+ .etag(ETAG)
+ .friendlyName(FRIENDLY_NAME)
+ .id(ID)
+ .lastModified(LAST_MODIFIED)
+ .location(LOCATION)
+ .selfLink(SELF_LINK)
+ .build();
+ private static final DatasetInfo DATASET_INFO_COMPLETE = DATASET_INFO.toBuilder()
+ .datasetId(DATASET_ID_COMPLETE)
+ .build();
+
+ @Test
+ public void testToBuilder() {
+ compareDatasets(DATASET_INFO, DATASET_INFO.toBuilder().build());
+ DatasetInfo datasetInfo = DATASET_INFO.toBuilder()
+ .datasetId(DatasetId.of("dataset2"))
+ .description("description2")
+ .build();
+ assertEquals(DatasetId.of("dataset2"), datasetInfo.datasetId());
+ assertEquals("description2", datasetInfo.description());
+ datasetInfo = datasetInfo.toBuilder().datasetId(DATASET_ID).description("description").build();
+ compareDatasets(DATASET_INFO, datasetInfo);
+ }
+
+ @Test
+ public void testToBuilderIncomplete() {
+ DatasetInfo datasetInfo = DatasetInfo.builder(DATASET_ID).build();
+ assertEquals(datasetInfo, datasetInfo.toBuilder().build());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertNull(DATASET_INFO.datasetId().project());
+ assertEquals(DATASET_ID, DATASET_INFO.datasetId());
+ assertEquals(ACCESS_RULES, DATASET_INFO.acl());
+ assertEquals(CREATION_TIME, DATASET_INFO.creationTime());
+ assertEquals(DEFAULT_TABLE_EXPIRATION, DATASET_INFO.defaultTableLifetime());
+ assertEquals(DESCRIPTION, DATASET_INFO.description());
+ assertEquals(ETAG, DATASET_INFO.etag());
+ assertEquals(FRIENDLY_NAME, DATASET_INFO.friendlyName());
+ assertEquals(ID, DATASET_INFO.id());
+ assertEquals(LAST_MODIFIED, DATASET_INFO.lastModified());
+ assertEquals(LOCATION, DATASET_INFO.location());
+ assertEquals(SELF_LINK, DATASET_INFO.selfLink());
+ assertEquals(DATASET_ID_COMPLETE, DATASET_INFO_COMPLETE.datasetId());
+ assertEquals(ACCESS_RULES, DATASET_INFO_COMPLETE.acl());
+ assertEquals(CREATION_TIME, DATASET_INFO_COMPLETE.creationTime());
+ assertEquals(DEFAULT_TABLE_EXPIRATION, DATASET_INFO_COMPLETE.defaultTableLifetime());
+ assertEquals(DESCRIPTION, DATASET_INFO_COMPLETE.description());
+ assertEquals(ETAG, DATASET_INFO_COMPLETE.etag());
+ assertEquals(FRIENDLY_NAME, DATASET_INFO_COMPLETE.friendlyName());
+ assertEquals(ID, DATASET_INFO_COMPLETE.id());
+ assertEquals(LAST_MODIFIED, DATASET_INFO_COMPLETE.lastModified());
+ assertEquals(LOCATION, DATASET_INFO_COMPLETE.location());
+ assertEquals(SELF_LINK, DATASET_INFO_COMPLETE.selfLink());
+ }
+
+ @Test
+ public void testToPbAndFromPb() {
+ compareDatasets(DATASET_INFO_COMPLETE, DatasetInfo.fromPb(DATASET_INFO_COMPLETE.toPb()));
+ DatasetInfo datasetInfo = DatasetInfo.builder("project", "dataset").build();
+ compareDatasets(datasetInfo, DatasetInfo.fromPb(datasetInfo.toPb()));
+ }
+
+ private void compareDatasets(DatasetInfo expected, DatasetInfo value) {
+ assertEquals(expected, value);
+ assertEquals(expected.datasetId(), value.datasetId());
+ assertEquals(expected.description(), value.description());
+ assertEquals(expected.etag(), value.etag());
+ assertEquals(expected.friendlyName(), value.friendlyName());
+ assertEquals(expected.id(), value.id());
+ assertEquals(expected.location(), value.location());
+ assertEquals(expected.selfLink(), value.selfLink());
+ assertEquals(expected.acl(), value.acl());
+ assertEquals(expected.creationTime(), value.creationTime());
+ assertEquals(expected.defaultTableLifetime(), value.defaultTableLifetime());
+ assertEquals(expected.lastModified(), value.lastModified());
+ }
+}
diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java
new file mode 100644
index 000000000000..93165724e11f
--- /dev/null
+++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gcloud.AuthCredentials;
+import com.google.gcloud.RetryParams;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.List;
+
+public class SerializationTest {
+
+ private static final Acl DOMAIN_ACCESS =
+ new Acl(new Acl.Domain("domain"), Acl.Role.WRITER);
+ private static final Acl GROUP_ACCESS =
+ new Acl(Acl.Group.ofAllAuthenticatedUsers(), Acl.Role.READER);
+ private static final Acl USER_ACCESS = new Acl(new Acl.User("user"), Acl.Role.OWNER);
+ private static final Acl VIEW_ACCESS =
+ new Acl(new Acl.View(TableId.of("project", "dataset", "table")), Acl.Role.WRITER);
+ private static final List ACCESS_RULES = ImmutableList.of(DOMAIN_ACCESS, GROUP_ACCESS,
+ VIEW_ACCESS, USER_ACCESS);
+ private static final Long CREATION_TIME = System.currentTimeMillis() - 10;
+ private static final Long DEFAULT_TABLE_EXPIRATION = 100L;
+ private static final String DESCRIPTION = "Description";
+ private static final String ETAG = "0xFF00";
+ private static final String FRIENDLY_NAME = "friendlyDataset";
+ private static final String ID = "P/D:1";
+ private static final Long LAST_MODIFIED = CREATION_TIME + 50;
+ private static final String LOCATION = "";
+ private static final String SELF_LINK = "http://bigquery/p/d";
+ private static final DatasetId DATASET_ID = DatasetId.of("project", "dataset");
+ private static final DatasetInfo DATASET_INFO = DatasetInfo.builder(DATASET_ID)
+ .acl(ACCESS_RULES)
+ .creationTime(CREATION_TIME)
+ .defaultTableLifetime(DEFAULT_TABLE_EXPIRATION)
+ .description(DESCRIPTION)
+ .etag(ETAG)
+ .friendlyName(FRIENDLY_NAME)
+ .id(ID)
+ .lastModified(LAST_MODIFIED)
+ .location(LOCATION)
+ .selfLink(SELF_LINK)
+ .build();
+ private static final TableId TABLE_ID = TableId.of("project", "dataset", "table");
+
+ @Test
+ public void testServiceOptions() throws Exception {
+ BigQueryOptions options = BigQueryOptions.builder()
+ .projectId("p1")
+ .authCredentials(AuthCredentials.createForAppEngine())
+ .build();
+ BigQueryOptions serializedCopy = serializeAndDeserialize(options);
+ assertEquals(options, serializedCopy);
+
+ options = options.toBuilder()
+ .projectId("p2")
+ .retryParams(RetryParams.getDefaultInstance())
+ .authCredentials(AuthCredentials.noCredentials())
+ .build();
+ serializedCopy = serializeAndDeserialize(options);
+ assertEquals(options, serializedCopy);
+ }
+
+ @Test
+ public void testModelAndRequests() throws Exception {
+ Serializable[] objects = {DOMAIN_ACCESS, GROUP_ACCESS, USER_ACCESS, VIEW_ACCESS, DATASET_ID,
+ DATASET_INFO, TABLE_ID};
+ for (Serializable obj : objects) {
+ Object copy = serializeAndDeserialize(obj);
+ assertEquals(obj, obj);
+ assertEquals(obj, copy);
+ assertNotSame(obj, copy);
+ assertEquals(copy, copy);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private T serializeAndDeserialize(T obj)
+ throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ try (ObjectOutputStream output = new ObjectOutputStream(bytes)) {
+ output.writeObject(obj);
+ }
+ try (ObjectInputStream input =
+ new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
+ return (T) input.readObject();
+ }
+ }
+}
diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/TableIdTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/TableIdTest.java
new file mode 100644
index 000000000000..9da050bf5951
--- /dev/null
+++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/TableIdTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.google.gcloud.bigquery;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class TableIdTest {
+
+ private static final TableId TABLE = TableId.of("dataset", "table");
+ private static final TableId TABLE_COMPLETE = TableId.of("project", "dataset", "table");
+
+ @Test
+ public void testOf() {
+ assertEquals(null, TABLE.project());
+ assertEquals("dataset", TABLE.dataset());
+ assertEquals("table", TABLE.table());
+ assertEquals("project", TABLE_COMPLETE.project());
+ assertEquals("dataset", TABLE_COMPLETE.dataset());
+ assertEquals("table", TABLE_COMPLETE.table());
+ }
+
+ @Test
+ public void testEquals() {
+ compareTableIds(TABLE, TableId.of("dataset", "table"));
+ compareTableIds(TABLE_COMPLETE, TableId.of("project", "dataset", "table"));
+ }
+
+ @Test
+ public void testToPbAndFromPb() {
+ compareTableIds(TABLE, TableId.fromPb(TABLE.toPb()));
+ compareTableIds(TABLE_COMPLETE, TableId.fromPb(TABLE_COMPLETE.toPb()));
+ }
+
+ private void compareTableIds(TableId expected, TableId value) {
+ assertEquals(expected, value);
+ assertEquals(expected.project(), value.project());
+ assertEquals(expected.dataset(), value.dataset());
+ assertEquals(expected.hashCode(), value.hashCode());
+ }
+}