Google APIs Client Library for C++ |
A C++ library for client applications to access Google APIs. |
This document discusses the JSON abstractions and implementations used by the client library for Data Objects in generated Service APIs.
Contents
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
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;
|
A capsule is a |
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.
Google APIs Client Library for C++