Google APIs Client Library for C++ A C++ library for client applications to access Google APIs.
Using the JSON Data Model

This document discusses the JSON abstractions and implementations used by the client library for Data Objects in generated Service APIs.

Contents

  1. Basic Concepts
  2. Typical Use Case Examples
    1. Simple Structures
    2. Dates and Times
    3. Arrays
    4. Associative Arrays
  3. JsonCppData Reference
    1. The JsonCppData base class
    2. JsonCppDataArray
    3. JsonCppDataAssociativeArray

Basic Concepts

The core client library interfaces refer to application data objects using the abstract class googleapis::client::SerializableJson. This class is so abstract that it only knows how to serialize and deserialize the instance in and out of JSON. In theory this makes the core client library independent of the JSON implementation.

The library provides a concrete implementation of this class with a ready-to-use interface in googleapis::client::JsonCppData. The data objects emitted by the code generator are derived from this class and provide a specialized interface for the class as defined by the specification in the service's Discovery Document. Because the abstract class is so generic, there isn't much to say about it so this document focuses on the JsonCppData implementation provided with the SDK.

See the section The JsonCppData base class later in this document for more information about JsonCppData.

Overview of Data Types used in the Data Models

JSON data objects are only used in the service-specific APIs. These data objects use the Primitive Types and String Types discussed among the Foundation Types. In addition, the code generator will use:
Type Description
[u]int(16|32|64) For JSON integer values. The JSON format determines the specific integer variant. The SDK defines all these in googleapis/base/integral_types.h. Note that JSON actually represents 64-bit integers as strings with the format '[u]int64' however the APIs will use native int64 for their public interface.
bool For JSON boolean values.
float | double For JSON number values.
string For JSON string values with 'byte' or no format.
googleapis::client::DateTime For JSON strings with 'date-time' format.
googleapis::client::JsonCppData For JSON 'object' or 'any' values. It is also the base class for custom typed Data Objects.
googleapis::client::JsonCppDataArray For JSON 'array' objects. A JsonCppDataArray is a subclass of JsonCppData. That is, it is itself a JsonCppData object. These arrays also provide a C++ iterator.
googleapis::client::JsonCppAssociativeArray For JSON 'map' objects. A JsonCppDataAssociativeArray is a subclass of JsonCppData. That is, it is itself a JsonCppData object. These maps also provide a C++ iterator.
template<typename T> googleapis::client::JsonCppDataCapsule;

JsonCppData objects require external Json::Value storage for their state, so they do not have default constructors. If you want to create a new instance, you need to provide the storage for it. This is awkward and inconvenient. Instead, you can create a capsule.

A capsule is a JsonCppData object that encapsulates its own storage so the it can be constructed with the default constructor. A capsule for type T can be used as a T, whether T is JsonCppData or any specialized derivation of it (i.e. array,s maps, and even service-specific data objects).

Typical Use Case Examples

Simple Structures

#include "googleapis/base/integral_types.h"
#include "googleapis/client/util/date_time.h"
#include "googleapis/client/data/jsoncpp_data.h"
#include "google/drive_api/drive_api.h"

using google_drive_api::File;
using googleapis::client::JsonCppData;
using googleapis::client::JsonCppDataCapsule;
using googleapis::client::DateTime;

void ProcessData(const JsonCppData& data);

void InitFileData(File* file) {
  DateTime now;
  int64 size = 123;  // just to illustrate using int64
  const StringPiece kText = "some sample tokens";  // for illustrative purposes.

  file->set_createdDate(now);            // Date-Time
  file->set_description("Sample File");  // string
  file->set_editable(true);              // boolean
  file->set_fileSize(size);              // int64 (string with int64 format)

  File::FileIndexableText& indexable_text = file->mutable_indexableText();
  indexable_text.set_text(kText);

  // This is just showing that changing the attribute obtained from a container
  // takes effect on the container itself.
  assert(indexable_test == file->indexableText().get_text());
}

void UseLocalData() {
  JsonCppDataCapsule<File> file;
  InitFileData(&file);
  ProcessData(file);
}

void UseDataFactory() {
  scoped_ptr<File> file(File::New());
  InitFileData(file.get());
  ProcessData(*file);
}

Dates and Times

#include "googleapis/client/util/date_time.h"
using googleapis::client::DateTime;

void Example() {
  DateTime now;   // Default constructor is current time

  // The following are all equivalent
  time_t epoch = now.ToEpochTime();
  DateTime from_epoch(epoch);

  struct tm utc;
  now.GetUniversalTime(&utc);
  DateTime from_utc(DateTime::DateTimeFromLocal(utc));

  struct tm local;
  now.GetLocalTime(&local);
  DateTime from_local(DateTime::DateTimeFromLocal(local));

  struct timeval tv;
  now.GetTimeval(&tv);
  DateTime from_timeval(tv);

  string str = now.ToString();
  DateTime from_str(str);
}

Arrays

#include "googleapis/client/data/jsoncpp_data.h"
using googleapis::client::JsonCppArray;
using googleapis::client::JsonCppData;

class MyData : public JsonCppData {
 public:
   int get_number() const;
   void set_number(int n);
};

void ExampleArray() {
  JsonCppCapsule<JsonCppArray<int> > primitive_array;
  JsonCppCapsule<JsonCppArray<MyData> > obj_array;

  for (int i = 0; i < 10; ++i) {
     primitive_array.set(i, 10 * i);   // cannot set with [] operator
     obj_array[i].set_number(10 * i);  // can use either [] or set_
  }

  for (int i = 0; i < 10; ++i) {
     // reading primitives can use [] operator
     assert(primitive_array[i] == obj_array[i].get_number());
  }

  // C++11 style iteration
  for (int i: primitive_array) {
  }

  // Tranditional iterator
  for (auto it = obj_array.begin(); it != obj_array.end(); +it) {
     int index = it.index();
     const MyData& data = *it;
  }

  // Can import/export to stl vectors.
  vector<int> v;
  primitive_array.Export(&v);
  primtive_array.Import(v);
}

Observe that non-object array types do not have a mutable [] operator. They only have an immutable accessor. You must use the array's set_ method. To read values from the array you can always use either the [] operator or get method.

Associative Arrays

#include "googleapis/client/data/jsoncpp_data.h"
using googleapis::client::JsonCppAssociativeArray;

void ExampleAssociativeArray() {
  JsonCppCapsule<JsonCppAssociativeArray<int> > aa;
  aa_put("one", 1);
  aa_put("two", 2);

  int value;
  if (aa_get("three", &value)) {
  }

  for (auto it = aa.begin(); it != aa.end(); ++it) {
      cout << it.key() << " = " << it.value();
  }
  for (const auto& elem : aa) {
      cout << elem.key() << " = " << elem.value();
  }
}

JsonCppData Reference

This section provides some additional reference documentation for using the JsonCppData class. All data objects generated by the code generator are derived from this class. At some point you may need to become more familiar with the details.

The JsonCppData base class

JsonCppData is defined in googleapis/client/data/jsoncpp_data.h

JsonCppData is implemented using the external open source JsonCpp library for convienence, with a more standard C++ API on top of it so that the specialized data objects generated for service-specific APIs look and feel more like C++. The resulting class has some quirks due to limitations in the underlying JsonCpp library interface for this usage pattern but client code using it can be written using a normal style.

JsonCppData is always a wrapper around an exernal Json::Value instance implemented by the JsonCpp library. Under normal circumstances, this is completely hidden from you. However if you are already using the JsonCpp library, or need direct access for some reason, the JsonCppData can provide direct access to the Json::Value instance.

The base JsonCppData stores all its state in the Json::Value it was constructed with. It merely delegates to that storage to manage its attributes. Specialized subclasses, such as data objects for service-specific APIs, provide wrapper functions to facilitate this and provide a more C++-like API.

#include "base/scoped_ptr.h"
#include "googleapis/client/data/jsoncpp_data.h"
using googleapis::client::JsonCppData;
using googleapis::client::JsonCppDataCapsule;

class MyData : public JsonCppData {
 public:
   explicit MyData(const Json::Value& storage) : JsonCppData(storage) {}
   explicit MyData(Json::Value* storage) : JsonCppData(storage) {}

   int get_number() const { return Storage("number").asInt(); }
   void set_number(int n) { *MutableStorage("number") = n; }

   const MyData next() const { return MyData(Storage("next")); }
   MyData next_mutable() { return MyData(MutableStorage("next")); }

   static MyData* New() { return new JsonCppDataCapsule<MyData>; }
};

void SampleUsage() {
   scoped_ptr<MyData> data(MyData::New());
   data->set_number(1);
   data->next_mutable().set_number(2);
   data->next_mutable().next_mutable().set_number(3);

   for (MyData elem = *data; !elem.IsNull(); elem = elem.next()) {
      cout << elem.get_number();
   }
}

JsonCppData instances are inherently const or mutable independent of language const decorators. This is determined at construction time. If the instance is constructed with a const Json::Value& reference then it will be immutable. If it is constructed with a Json::Value* pointer it will be mutable. The API uses const decorators as any other class would to use normal C++ compiler protection. However the objects are self-enforcing at runtime. This means even if you cast away the language const at compile time, the runtime will know and not let you perform the action. This behavior is an anomaly specific to JsonCppData as a solution to some limitations in the underlying JsonCpp library which does not directly lend itself to the client libraries usage pattern.

Json::Value  storage;

MyData immutable_data(storage);
MyData mutable_data(&storage);

assert(mutable_data.IsMutable() == true);
assert(immutable_data.IsMutable() == false);

Json::Value* ptr = mutable_data.MutableStorage();  // ok

// The following will CHECK fail as an illegal operation.
ptr = immutable_data.MutableStorage();

The API is designed such that as long as you preserve constness then everything will work properly. But you const_cast away constness then the library will catch you.

The proper way to have constructed immutable_data in the previous example would be:
const MyData immutable_data(storage);
That way the compiler would have caught the invalid call to immutable_data.MutableStorage() because of the call from a const instance to a non-const method.

JsonCppDataArray

JsonCppDataAssociativeArray