Structured parcelables.

Example:
parcelable StructuredParcelable {
    int[] shouldContainThreeFs;
    int f;
    @utf8InCpp String shouldBeJerry;
}

Bug: 110758329
Test: runtests.sh
Change-Id: I4af2317fba33a0024f354828ad0b310bf8fe8752
diff --git a/Android.bp b/Android.bp
index 78207e5..95809a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -166,6 +166,7 @@
     srcs: [
         "tests/android/aidl/tests/ITestService.aidl",
         "tests/android/aidl/tests/INamedCallback.aidl",
+        "tests/android/aidl/tests/StructuredParcelable.aidl",
         "tests/simple_parcelable.cpp",
     ],
 }
@@ -208,6 +209,7 @@
     srcs: [
         "tests/android/aidl/tests/INamedCallback.aidl",
         "tests/android/aidl/tests/ITestService.aidl",
+        "tests/android/aidl/tests/StructuredParcelable.aidl",
         "tests/java_app/src/android/aidl/tests/NullableTests.java",
         "tests/java_app/src/android/aidl/tests/SimpleParcelable.java",
         "tests/java_app/src/android/aidl/tests/TestFailException.java",
diff --git a/aidl.cpp b/aidl.cpp
index 5cc186f..48f72e6 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -170,6 +170,25 @@
   return success;
 }
 
+int check_types(const string& filename, const AidlStructuredParcelable* parcel,
+                TypeNamespace* types) {
+  int err = 0;
+  for (const auto& v : parcel->GetFields()) {
+    if (!types->MaybeAddContainerType(v->GetType())) {
+      err = 1;  // return type is invalid
+    }
+
+    const ValidatableType* type = types->GetReturnType(v->GetType(), filename, *parcel);
+    if (!type) {
+      err = 1;
+    }
+
+    v->GetMutableType()->SetLanguageType(type);
+  }
+
+  return err;
+}
+
 int check_types(const string& filename,
                 const AidlInterface* c,
                 TypeNamespace* types) {
@@ -290,8 +309,7 @@
   return true;
 }
 
-bool write_cpp_dep_file(const CppOptions& options,
-                        const AidlInterface& interface,
+bool write_cpp_dep_file(const CppOptions& options, const AidlDefinedType& defined_type,
                         const vector<unique_ptr<AidlImport>>& imports,
                         const IoDelegate& io_delegate) {
   using ::android::aidl::cpp::HeaderFile;
@@ -323,7 +341,7 @@
                          ClassNames::SERVER,
                          ClassNames::INTERFACE}) {
       headers.push_back(options.OutputHeaderDir() + '/' +
-                        HeaderFile(interface, c, false /* use_os_sep */));
+                        HeaderFile(defined_type, c, false /* use_os_sep */));
     }
 
     writer->Write("\n");
@@ -336,33 +354,32 @@
   return true;
 }
 
-string generate_outputFileName(const JavaOptions& options,
-                               const AidlInterface& interface) {
-    const string& name = interface.GetName();
-    string package = interface.GetPackage();
-    string result;
+string generate_outputFileName(const JavaOptions& options, const AidlDefinedType& defined_type) {
+  const string& name = defined_type.GetName();
+  string package = defined_type.GetPackage();
+  string result;
 
-    // create the path to the destination folder based on the
-    // interface package name
-    result = options.output_base_folder_;
-    result += OS_PATH_SEPARATOR;
+  // create the path to the destination folder based on the
+  // defined_type package name
+  result = options.output_base_folder_;
+  result += OS_PATH_SEPARATOR;
 
-    string packageStr = package;
-    size_t len = packageStr.length();
-    for (size_t i=0; i<len; i++) {
-        if (packageStr[i] == '.') {
-            packageStr[i] = OS_PATH_SEPARATOR;
-        }
+  string packageStr = package;
+  size_t len = packageStr.length();
+  for (size_t i = 0; i < len; i++) {
+    if (packageStr[i] == '.') {
+      packageStr[i] = OS_PATH_SEPARATOR;
     }
+  }
 
-    result += packageStr;
+  result += packageStr;
 
-    // add the filename by replacing the .aidl extension to .java
-    result += OS_PATH_SEPARATOR;
-    result.append(name, 0, name.find('.'));
-    result += ".java";
+  // add the filename by replacing the .aidl extension to .java
+  result += OS_PATH_SEPARATOR;
+  result.append(name, 0, name.find('.'));
+  result += ".java";
 
-    return result;
+  return result;
 }
 
 int check_and_assign_method_ids(const char * filename,
@@ -543,15 +560,12 @@
   return success;
 }
 
-AidlError load_and_validate_aidl(
-    const std::vector<std::string>& preprocessed_files,
-    const std::vector<std::string>& import_paths,
-    const std::string& input_file_name,
-    const bool generate_traces,
-    const IoDelegate& io_delegate,
-    TypeNamespace* types,
-    std::unique_ptr<AidlInterface>* returned_interface,
-    std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
+AidlError load_and_validate_aidl(const std::vector<std::string>& preprocessed_files,
+                                 const std::vector<std::string>& import_paths,
+                                 const std::string& input_file_name, const bool generate_traces,
+                                 const IoDelegate& io_delegate, TypeNamespace* types,
+                                 std::unique_ptr<AidlDefinedType>* returned_type,
+                                 std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
   AidlError err = AidlError::OK;
 
   std::map<AidlImport*,std::unique_ptr<AidlDocument>> docs;
@@ -575,18 +589,23 @@
   AidlDocument* parsed_doc = p.GetDocument();
 
   unique_ptr<AidlInterface> interface(parsed_doc->ReleaseInterface());
+  unique_ptr<AidlStructuredParcelable> parcelable(parsed_doc->ReleaseStructuredParcelable());
 
-  if (!interface) {
-    LOG(ERROR) << "refusing to generate code from aidl file defining "
-                  "parcelable";
+  CHECK(interface == nullptr || parcelable == nullptr);  // grammar invariant
+
+  AidlDefinedType* defined_type = interface.get();
+  if (defined_type == nullptr) defined_type = parcelable.get();
+
+  if (!defined_type) {
+    LOG(ERROR)
+        << "cannot generate code from aidl file w/o either one interface or structured parcelable";
     return AidlError::FOUND_PARCELABLE;
   }
 
-  if (!check_filename(input_file_name.c_str(), interface->GetPackage(),
-                      interface->GetName(), interface->GetLine()) ||
-      !types->IsValidPackage(interface->GetPackage())) {
-    LOG(ERROR) << "Invalid package declaration '" << interface->GetPackage()
-               << "'";
+  if (!check_filename(input_file_name.c_str(), defined_type->GetPackage(), defined_type->GetName(),
+                      defined_type->GetLine()) ||
+      !types->IsValidPackage(defined_type->GetPackage())) {
+    LOG(ERROR) << "Invalid package declaration '" << defined_type->GetPackage() << "'";
     return AidlError::BAD_PACKAGE;
   }
 
@@ -626,14 +645,22 @@
     return err;
   }
 
-  // gather the types that have been declared
-  if (!types->AddBinderType(*interface.get(), input_file_name)) {
-    err = AidlError::BAD_TYPE;
+  if (interface) {
+    // gather the types that have been declared
+    if (!types->AddBinderType(*interface.get(), input_file_name)) {
+      err = AidlError::BAD_TYPE;
+    }
+
+    interface->SetGenerateTraces(generate_traces);
   }
 
-  interface->SetLanguageType(types->GetInterfaceType(*interface));
+  if (parcelable) {
+    if (!types->AddParcelableType(*parcelable.get(), input_file_name)) {
+      err = AidlError::BAD_TYPE;
+    }
+  }
 
-  interface->SetGenerateTraces(generate_traces);
+  defined_type->SetLanguageType(types->GetDefinedType(*defined_type));
 
   for (const auto& import : p.GetImports()) {
     // If we skipped an unresolved import above (see comment there) we'll have
@@ -649,25 +676,27 @@
   }
 
   // check the referenced types in parsed_doc to make sure we've imported them
-  if (check_types(input_file_name, interface.get(), types) != 0) {
+  if (interface && check_types(input_file_name, interface.get(), types) != 0) {
+    err = AidlError::BAD_TYPE;
+  }
+  if (parcelable && check_types(input_file_name, parcelable.get(), types) != 0) {
     err = AidlError::BAD_TYPE;
   }
   if (err != AidlError::OK) {
     return err;
   }
 
-
   // assign method ids and validate.
-  if (check_and_assign_method_ids(input_file_name.c_str(),
-                                  interface->GetMethods()) != 0) {
+  if (interface &&
+      check_and_assign_method_ids(input_file_name.c_str(), interface->GetMethods()) != 0) {
     return AidlError::BAD_METHOD_ID;
   }
-  if (!validate_constants(*interface)) {
+  if (interface && !validate_constants(*interface)) {
     return AidlError::BAD_CONSTANTS;
   }
 
-  if (returned_interface)
-    *returned_interface = std::move(interface);
+  if (returned_type && interface) *returned_type = std::move(interface);
+  if (returned_type && parcelable) *returned_type = std::move(parcelable);
 
   if (returned_imports)
     p.ReleaseImports(returned_imports);
@@ -679,45 +708,36 @@
 
 int compile_aidl_to_cpp(const CppOptions& options,
                         const IoDelegate& io_delegate) {
-  unique_ptr<AidlInterface> interface;
+  unique_ptr<AidlDefinedType> defined_type;
   std::vector<std::unique_ptr<AidlImport>> imports;
   unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
   types->Init();
   AidlError err = internals::load_and_validate_aidl(
       std::vector<std::string>{},  // no preprocessed files
-      options.ImportPaths(),
-      options.InputFileName(),
-      options.ShouldGenTraces(),
-      io_delegate,
-      types.get(),
-      &interface,
-      &imports);
+      options.ImportPaths(), options.InputFileName(), options.ShouldGenTraces(), io_delegate,
+      types.get(), &defined_type, &imports);
   if (err != AidlError::OK) {
     return 1;
   }
 
-  if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) {
+  CHECK(defined_type != nullptr);
+
+  if (!write_cpp_dep_file(options, *defined_type, imports, io_delegate)) {
     return 1;
   }
 
-  return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1;
+  return (cpp::GenerateCpp(options, *types, *defined_type, io_delegate)) ? 0 : 1;
 }
 
 int compile_aidl_to_java(const JavaOptions& options,
                          const IoDelegate& io_delegate) {
-  unique_ptr<AidlInterface> interface;
+  unique_ptr<AidlDefinedType> defined_type;
   std::vector<std::unique_ptr<AidlImport>> imports;
   unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
   types->Init();
   AidlError aidl_err = internals::load_and_validate_aidl(
-      options.preprocessed_files_,
-      options.import_paths_,
-      options.input_file_name_,
-      options.gen_traces_,
-      io_delegate,
-      types.get(),
-      &interface,
-      &imports);
+      options.preprocessed_files_, options.import_paths_, options.input_file_name_,
+      options.gen_traces_, io_delegate, types.get(), &defined_type, &imports);
   if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) {
     // We aborted code generation because this file contains parcelables.
     // However, we were not told to complain if we find parcelables.
@@ -730,10 +750,12 @@
     return 1;
   }
 
+  CHECK(defined_type != nullptr);
+
   string output_file_name = options.output_file_name_;
   // if needed, generate the output file name from the base folder
   if (output_file_name.empty() && !options.output_base_folder_.empty()) {
-    output_file_name = generate_outputFileName(options, *interface);
+    output_file_name = generate_outputFileName(options, *defined_type);
   }
 
   // make sure the folders of the output file all exists
@@ -745,8 +767,8 @@
     return 1;
   }
 
-  return generate_java(output_file_name, options.input_file_name_.c_str(),
-                       interface.get(), types.get(), io_delegate, options);
+  return generate_java(output_file_name, options.input_file_name_.c_str(), defined_type.get(),
+                       types.get(), io_delegate, options);
 }
 
 bool preprocess_aidl(const JavaOptions& options,
diff --git a/aidl.h b/aidl.h
index eb260c0..7eb22c2 100644
--- a/aidl.h
+++ b/aidl.h
@@ -54,15 +54,12 @@
 
 namespace internals {
 
-AidlError load_and_validate_aidl(
-    const std::vector<std::string>& preprocessed_files,
-    const std::vector<std::string>& import_paths,
-    const std::string& input_file_name,
-    const bool generate_traces,
-    const IoDelegate& io_delegate,
-    TypeNamespace* types,
-    std::unique_ptr<AidlInterface>* returned_interface,
-    std::vector<std::unique_ptr<AidlImport>>* returned_imports);
+AidlError load_and_validate_aidl(const std::vector<std::string>& preprocessed_files,
+                                 const std::vector<std::string>& import_paths,
+                                 const std::string& input_file_name, const bool generate_traces,
+                                 const IoDelegate& io_delegate, TypeNamespace* types,
+                                 std::unique_ptr<AidlDefinedType>* returned_type,
+                                 std::vector<std::unique_ptr<AidlImport>>* returned_imports);
 
 bool parse_preprocessed_file(const IoDelegate& io_delegate,
                              const std::string& filename, TypeNamespace* types);
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 95a3369..3f9e78c 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -49,20 +49,23 @@
   return name_ + (is_array_ ? "[]" : "");
 }
 
-AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type,
-                           std::string name, unsigned line)
-    : type_(type),
+AidlVariableDeclaration::AidlVariableDeclaration(AidlType* type, std::string name, unsigned line)
+    : type_(type), name_(name), line_(line) {}
+
+string AidlVariableDeclaration::ToString() const {
+  return type_->ToString() + " " + name_;
+}
+
+AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type, std::string name,
+                           unsigned line)
+    : AidlVariableDeclaration(type, name, line),
       direction_(direction),
-      direction_specified_(true),
-      name_(name),
-      line_(line) {}
+      direction_specified_(true) {}
 
 AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line)
-    : type_(type),
+    : AidlVariableDeclaration(type, name, line),
       direction_(AidlArgument::IN_DIR),
-      direction_specified_(false),
-      name_(name),
-      line_(line) {}
+      direction_specified_(false) {}
 
 string AidlArgument::ToString() const {
   string ret;
@@ -81,9 +84,7 @@
     }
   }
 
-  ret += type_->ToString();
-  ret += " ";
-  ret += name_;
+  ret += AidlVariableDeclaration::ToString();
 
   return ret;
 }
@@ -188,6 +189,11 @@
   }
 }
 
+AidlStructuredParcelable::AidlStructuredParcelable(
+    AidlQualifiedName* name, unsigned line, const std::vector<std::string>& package,
+    std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables)
+    : AidlParcelable(name, line, package, "" /*cpp_header*/), variables_(std::move(*variables)) {}
+
 AidlInterface::AidlInterface(const std::string& name, unsigned line,
                              const std::string& comments, bool oneway,
                              std::vector<std::unique_ptr<AidlMember>>* members,
@@ -217,6 +223,26 @@
 AidlDocument::AidlDocument(AidlInterface* interface)
     : interface_(interface) {}
 
+AidlStructuredParcelable* AidlDocument::ReleaseStructuredParcelable() {
+  if (parcelables_.size() == 0) {
+    return nullptr;
+  }
+
+  AidlStructuredParcelable* ret = nullptr;
+  for (auto& p : parcelables_) {
+    if (p->AsStructuredParcelable() == nullptr) continue;
+
+    if (ret != nullptr) {
+      LOG(ERROR) << "AIDL only supports one structured parcelable per file.";
+      return nullptr;
+    }
+
+    ret = static_cast<AidlStructuredParcelable*>(p.release());
+  }
+
+  return ret;
+}
+
 AidlQualifiedName::AidlQualifiedName(std::string term,
                                      std::string comments)
     : terms_({term}),
diff --git a/aidl_language.h b/aidl_language.h
index ddbd58a..91fbf17 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -108,7 +108,27 @@
   DISALLOW_COPY_AND_ASSIGN(AidlType);
 };
 
-class AidlArgument : public AidlNode {
+class AidlVariableDeclaration : public AidlNode {
+ public:
+  AidlVariableDeclaration(AidlType* type, std::string name, unsigned line);
+  virtual ~AidlVariableDeclaration() = default;
+
+  std::string GetName() const { return name_; }
+  int GetLine() const { return line_; }
+  const AidlType& GetType() const { return *type_; }
+  AidlType* GetMutableType() { return type_.get(); }
+
+  std::string ToString() const;
+
+ private:
+  std::unique_ptr<AidlType> type_;
+  std::string name_;
+  unsigned line_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlVariableDeclaration);
+};
+
+class AidlArgument : public AidlVariableDeclaration {
  public:
   enum Direction { IN_DIR = 1, OUT_DIR = 2, INOUT_DIR = 3 };
 
@@ -122,19 +142,11 @@
   bool IsIn() const { return direction_ & IN_DIR; }
   bool DirectionWasSpecified() const { return direction_specified_; }
 
-  std::string GetName() const { return name_; }
-  int GetLine() const { return line_; }
-  const AidlType& GetType() const { return *type_; }
-  AidlType* GetMutableType() { return type_.get(); }
-
   std::string ToString() const;
 
  private:
-  std::unique_ptr<AidlType> type_;
   Direction direction_;
   bool direction_specified_;
-  std::string name_;
-  unsigned line_;
 
   DISALLOW_COPY_AND_ASSIGN(AidlArgument);
 };
@@ -245,6 +257,7 @@
 };
 
 class AidlParcelable;
+class AidlStructuredParcelable;
 class AidlInterface;
 class AidlDocument : public AidlNode {
  public:
@@ -254,11 +267,11 @@
 
   const AidlInterface* GetInterface() const { return interface_.get(); }
   AidlInterface* ReleaseInterface() { return interface_.release(); }
+  AidlStructuredParcelable* ReleaseStructuredParcelable();
 
   const std::vector<std::unique_ptr<AidlParcelable>>& GetParcelables() const {
     return parcelables_;
   }
-
   void AddParcelable(AidlParcelable* parcelable) {
     parcelables_.push_back(std::unique_ptr<AidlParcelable>(parcelable));
   }
@@ -302,8 +315,13 @@
   std::string GetCanonicalName() const;
   const std::vector<std::string>& GetSplitPackage() const { return package_; }
 
+  virtual const AidlStructuredParcelable* AsStructuredParcelable() const { return nullptr; }
+  virtual const AidlInterface* AsInterface() const { return nullptr; }
+
  private:
   const std::vector<std::string> package_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlDefinedType);
 };
 
 class AidlParcelable : public AidlDefinedType {
@@ -315,6 +333,8 @@
 
   // C++ uses "::" instead of "." to refer to a inner class.
   std::string GetCppName() const { return name_->GetColonName(); }
+
+  void SetCppHeader(const std::string& cpp_header) { cpp_header_ = cpp_header; }
   std::string GetCppHeader() const { return cpp_header_; }
 
  private:
@@ -324,6 +344,24 @@
   DISALLOW_COPY_AND_ASSIGN(AidlParcelable);
 };
 
+class AidlStructuredParcelable : public AidlParcelable {
+ public:
+  AidlStructuredParcelable(AidlQualifiedName* name, unsigned line,
+                           const std::vector<std::string>& package,
+                           std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables);
+
+  const std::vector<std::unique_ptr<AidlVariableDeclaration>>& GetFields() const {
+    return variables_;
+  }
+
+  virtual const AidlStructuredParcelable* AsStructuredParcelable() const { return this; }
+
+ private:
+  const std::vector<std::unique_ptr<AidlVariableDeclaration>> variables_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlStructuredParcelable);
+};
+
 class AidlInterface : public AidlDefinedType {
  public:
   AidlInterface(const std::string& name, unsigned line,
@@ -348,6 +386,8 @@
     return generate_traces_;
   }
 
+  virtual const AidlInterface* AsInterface() const { return this; }
+
  private:
   bool oneway_;
   std::vector<std::unique_ptr<AidlMethod>> methods_;
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index 68997b7..529abba 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -30,6 +30,8 @@
     AidlArgument* arg;
     AidlArgument::Direction direction;
     std::vector<std::unique_ptr<AidlArgument>>* arg_list;
+    AidlVariableDeclaration* variable;
+    std::vector<std::unique_ptr<AidlVariableDeclaration>>* variable_list;
     AidlMethod* method;
     AidlMember* constant;
     std::vector<std::unique_ptr<AidlMember>>* members;
@@ -49,6 +51,8 @@
 
 %type<parcelable_list> parcelable_decls
 %type<parcelable> parcelable_decl
+%type<variable_list> variable_decls
+%type<variable> variable_decl
 %type<members> members
 %type<interface_obj> interface_decl
 %type<method> method_decl
@@ -114,9 +118,17 @@
 parcelable_decls
  :
   { $$ = new AidlDocument(); }
- | parcelable_decls parcelable_decl {
+ | parcelable_decls annotation_list parcelable_decl {
    $$ = $1;
-   $$->AddParcelable($2);
+
+   if ($2 != AidlType::AnnotationNone && !$3->AsStructuredParcelable()) {
+     std::cerr << ps->FileName() << ":" << @3 << ": unstructured parcelables cannot be annotated"
+               << std::endl;
+     ps->AddError();
+   }
+
+   $3->Annotate($2);
+   $$->AddParcelable($3);
   }
  | parcelable_decls error {
     ps->AddError();
@@ -130,11 +142,34 @@
  | PARCELABLE qualified_name CPP_HEADER C_STR ';' {
     $$ = new AidlParcelable($2, @2.begin.line, ps->Package(), $4->GetText());
   }
+ | PARCELABLE identifier '{' variable_decls '}' {
+    AidlQualifiedName* name = new AidlQualifiedName($2->GetText(), $2->GetComments());
+    $$ = new AidlStructuredParcelable(name, @2.begin.line, ps->Package(), $4);
+ }
  | PARCELABLE error ';' {
     ps->AddError();
     $$ = NULL;
   };
 
+variable_decls
+ : /* empty */ {
+    $$ = new std::vector<std::unique_ptr<AidlVariableDeclaration>>; }
+ | variable_decls variable_decl {
+    $$ = $1;
+    if ($2 != nullptr) {
+      $$->push_back(std::unique_ptr<AidlVariableDeclaration>($2));
+    }
+ };
+
+variable_decl
+ : type identifier ';' {
+   $$ = new AidlVariableDeclaration($1, $2->GetText(), @2.begin.line);
+ }
+ | error ';' {
+   ps->AddError();
+   $$ = nullptr;
+ }
+
 interface_decl
  : annotation_list INTERFACE identifier '{' members '}' {
     $$ = new AidlInterface($3->GetText(), @2.begin.line, $2->GetComments(),
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 597a766..6e4f4fc 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -69,12 +69,10 @@
     cpp_types_.Init();
   }
 
-  unique_ptr<AidlInterface> Parse(const string& path,
-                                  const string& contents,
-                                  TypeNamespace* types,
-                                  AidlError* error = nullptr) {
+  unique_ptr<AidlDefinedType> Parse(const string& path, const string& contents,
+                                    TypeNamespace* types, AidlError* error = nullptr) {
     io_delegate_.SetFileContents(path, contents);
-    unique_ptr<AidlInterface> ret;
+    unique_ptr<AidlDefinedType> ret;
     std::vector<std::unique_ptr<AidlImport>> imports;
     AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl(
         preprocessed_files_,
@@ -151,9 +149,10 @@
                      (is_nullable) ? "@nullable" : ""),
         &cpp_types_);
     ASSERT_NE(nullptr, parse_result);
-    ASSERT_FALSE(parse_result->GetMethods().empty());
-    EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsNullable(),
-              is_nullable);
+    const AidlInterface* interface = parse_result->AsInterface();
+    ASSERT_NE(nullptr, interface);
+    ASSERT_FALSE(interface->GetMethods().empty());
+    EXPECT_EQ(interface->GetMethods()[0]->GetType().IsNullable(), is_nullable);
   }
 }
 
@@ -165,9 +164,10 @@
                      (is_utf8) ? "@utf8InCpp" : ""),
         &cpp_types_);
     ASSERT_NE(nullptr, parse_result);
-    ASSERT_FALSE(parse_result->GetMethods().empty());
-    EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsUtf8InCpp(),
-              is_utf8);
+    const AidlInterface* interface = parse_result->AsInterface();
+    ASSERT_NE(nullptr, interface);
+    ASSERT_FALSE(interface->GetMethods().empty());
+    EXPECT_EQ(interface->GetMethods()[0]->GetType().IsUtf8InCpp(), is_utf8);
   }
 }
 
@@ -314,7 +314,9 @@
            &cpp_types_,
            &reported_error);
   EXPECT_NE(nullptr, cpp_parse_result);
-  const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
+  const AidlInterface* interface = cpp_parse_result->AsInterface();
+  ASSERT_NE(nullptr, interface);
+  const auto& cpp_int_constants = interface->GetIntConstants();
   EXPECT_EQ((size_t)1, cpp_int_constants.size());
   EXPECT_EQ("POSITIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
   EXPECT_EQ(245, cpp_int_constants[0]->GetValue());
@@ -332,7 +334,9 @@
            &cpp_types_,
            &reported_error);
   EXPECT_NE(nullptr, cpp_parse_result);
-  const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
+  const AidlInterface* interface = cpp_parse_result->AsInterface();
+  ASSERT_NE(nullptr, interface);
+  const auto& cpp_int_constants = interface->GetIntConstants();
   EXPECT_EQ((size_t)1, cpp_int_constants.size());
   EXPECT_EQ("NEGATIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
   EXPECT_EQ(-1, cpp_int_constants[0]->GetValue());
diff --git a/ast_cpp.cpp b/ast_cpp.cpp
index 14fa8a6..7af94ac 100644
--- a/ast_cpp.cpp
+++ b/ast_cpp.cpp
@@ -29,6 +29,12 @@
 namespace aidl {
 namespace cpp {
 
+LiteralDecl::LiteralDecl(const std::string& expression) : expression_(expression) {}
+
+void LiteralDecl::Write(CodeWriter* to) const {
+  to->Write("%s", expression_.c_str());
+}
+
 ClassDecl::ClassDecl(const std::string& name, const std::string& parent)
     : name_(name),
       parent_(parent) {}
diff --git a/ast_cpp.h b/ast_cpp.h
index bb251ec..9fff316 100644
--- a/ast_cpp.h
+++ b/ast_cpp.h
@@ -49,6 +49,18 @@
   DISALLOW_COPY_AND_ASSIGN(Declaration);
 };  // class Declaration
 
+class LiteralDecl : public Declaration {
+ public:
+  explicit LiteralDecl(const std::string& expression);
+  ~LiteralDecl() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string expression_;
+
+  DISALLOW_COPY_AND_ASSIGN(LiteralDecl);
+};  // class LiteralDecl
+
 class ClassDecl : public Declaration {
  public:
   ClassDecl(const std::string& name,
diff --git a/ast_java.cpp b/ast_java.cpp
index c534e4e..9499ec6 100644
--- a/ast_java.cpp
+++ b/ast_java.cpp
@@ -421,6 +421,10 @@
   }
 }
 
+void LiteralClassElement::Write(CodeWriter* to) const {
+  to->Write("%s", element.c_str());
+}
+
 void IntConstant::Write(CodeWriter* to) const {
   WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
   to->Write("int %s = %d;\n", name.c_str(), value);
diff --git a/ast_java.h b/ast_java.h
index c5ded58..b28e7b0 100644
--- a/ast_java.h
+++ b/ast_java.h
@@ -326,6 +326,15 @@
   void Write(CodeWriter* to) const override;
 };
 
+struct LiteralClassElement : public ClassElement {
+  std::string element;
+
+  LiteralClassElement(std::string e) : element(e) {}
+  virtual ~LiteralClassElement() = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
 struct IntConstant : public ClassElement {
   const std::string name;
   const int value;
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index b6181eb..f7e90cf 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -81,6 +81,13 @@
   return unique_ptr<AstNode>(ret);
 }
 
+unique_ptr<AstNode> ReturnOnStatusNotOk() {
+  IfStatement* ret = new IfStatement(new Comparison(new LiteralExpression(kAndroidStatusVarName),
+                                                    "!=", new LiteralExpression(kAndroidStatusOk)));
+  ret->OnTrue()->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+  return unique_ptr<AstNode>(ret);
+}
+
 string UpperCase(const std::string& s) {
   string result = s;
   for (char& c : result)
@@ -199,8 +206,8 @@
   return true;
 }
 
-string ClassName(const AidlInterface& interface, ClassNames type) {
-  string c_name = interface.GetName();
+string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
+  string c_name = defined_type.GetName();
 
   if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
     c_name = c_name.substr(1);
@@ -221,17 +228,15 @@
   return c_name;
 }
 
-string BuildHeaderGuard(const AidlInterface& interface,
-                        ClassNames header_type) {
-  string class_name = ClassName(interface, header_type);
+string BuildHeaderGuard(const AidlDefinedType& defined_type, ClassNames header_type) {
+  string class_name = ClassName(defined_type, header_type);
   for (size_t i = 1; i < class_name.size(); ++i) {
     if (isupper(class_name[i])) {
       class_name.insert(i, "_");
       ++i;
     }
   }
-  string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_",
-                            interface.GetPackage().c_str(),
+  string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_", defined_type.GetPackage().c_str(),
                             class_name.c_str());
   for (char& c : ret) {
     if (c == '.') {
@@ -772,6 +777,82 @@
       NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}};
 }
 
+std::unique_ptr<Document> BuildParcelHeader(const TypeNamespace& /*types*/,
+                                            const AidlStructuredParcelable& parcel) {
+  unique_ptr<ClassDecl> parcel_class{new ClassDecl{parcel.GetName(), "::android::Parcelable"}};
+
+  set<string> includes = {kStatusHeader, kParcelHeader};
+  for (const auto& variable : parcel.GetFields()) {
+    const Type* type = variable->GetType().GetLanguageType<Type>();
+    type->GetHeaders(&includes);
+  }
+
+  for (const auto& variable : parcel.GetFields()) {
+    const Type* type = variable->GetType().GetLanguageType<Type>();
+
+    parcel_class->AddPublic(std::unique_ptr<LiteralDecl>(new LiteralDecl(
+        StringPrintf("%s %s;\n", type->CppType().c_str(), variable->GetName().c_str()))));
+  }
+
+  unique_ptr<MethodDecl> read(new MethodDecl(kAndroidStatusLiteral, "readFromParcel",
+                                             ArgList("const Parcel* _aidl_parcel"),
+                                             MethodDecl::IS_OVERRIDE));
+  parcel_class->AddPublic(std::move(read));
+  unique_ptr<MethodDecl> write(new MethodDecl(kAndroidStatusLiteral, "writeToParcel",
+                                              ArgList("Parcel* _aidl_parcel"),
+                                              MethodDecl::IS_OVERRIDE | MethodDecl::IS_CONST));
+  parcel_class->AddPublic(std::move(write));
+
+  return unique_ptr<Document>{new CppHeader{
+      BuildHeaderGuard(parcel, ClassNames::BASE), vector<string>(includes.begin(), includes.end()),
+      NestInNamespaces(std::move(parcel_class), parcel.GetSplitPackage())}};
+}
+std::unique_ptr<Document> BuildParcelSource(const TypeNamespace& types,
+                                            const AidlStructuredParcelable& parcel) {
+  unique_ptr<MethodImpl> read{new MethodImpl{kAndroidStatusLiteral, parcel.GetName(),
+                                             "readFromParcel",
+                                             ArgList("const Parcel* _aidl_parcel")}};
+  StatementBlock* read_block = read->GetStatementBlock();
+  read_block->AddLiteral(
+      StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk));
+  for (const auto& variable : parcel.GetFields()) {
+    string method = variable->GetType().GetLanguageType<Type>()->ReadFromParcelMethod();
+
+    read_block->AddStatement(new Assignment(
+        kAndroidStatusVarName, new MethodCall(StringPrintf("_aidl_parcel->%s", method.c_str()),
+                                              ArgList("&" + variable->GetName()))));
+    read_block->AddStatement(ReturnOnStatusNotOk());
+  }
+  read_block->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+
+  unique_ptr<MethodImpl> write{new MethodImpl{kAndroidStatusLiteral, parcel.GetName(),
+                                              "writeToParcel", ArgList("Parcel* _aidl_parcel"),
+                                              true /*const*/}};
+  StatementBlock* write_block = write->GetStatementBlock();
+  write_block->AddLiteral(
+      StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk));
+  for (const auto& variable : parcel.GetFields()) {
+    string method = variable->GetType().GetLanguageType<Type>()->WriteToParcelMethod();
+
+    write_block->AddStatement(new Assignment(
+        kAndroidStatusVarName, new MethodCall(StringPrintf("_aidl_parcel->%s", method.c_str()),
+                                              ArgList(variable->GetName()))));
+    write_block->AddStatement(ReturnOnStatusNotOk());
+  }
+  write_block->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+
+  vector<unique_ptr<Declaration>> file_decls;
+  file_decls.push_back(std::move(read));
+  file_decls.push_back(std::move(write));
+
+  set<string> includes = {};
+  parcel.GetLanguageType<Type>()->GetHeaders(&includes);
+
+  return unique_ptr<Document>{
+      new CppSource{vector<string>(includes.begin(), includes.end()),
+                    NestInNamespaces(std::move(file_decls), parcel.GetSplitPackage())}};
+}
+
 bool WriteHeader(const CppOptions& options,
                  const TypeNamespace& types,
                  const AidlInterface& interface,
@@ -813,10 +894,8 @@
 
 using namespace internals;
 
-string HeaderFile(const AidlInterface& interface,
-                  ClassNames class_type,
-                  bool use_os_sep) {
-  string file_path = interface.GetPackage();
+string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type, bool use_os_sep) {
+  string file_path = defined_type.GetPackage();
   for (char& c: file_path) {
     if (c == '.') {
       c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
@@ -825,16 +904,14 @@
   if (!file_path.empty()) {
     file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
   }
-  file_path += ClassName(interface, class_type);
+  file_path += ClassName(defined_type, class_type);
   file_path += ".h";
 
   return file_path;
 }
 
-bool GenerateCpp(const CppOptions& options,
-                 const TypeNamespace& types,
-                 const AidlInterface& interface,
-                 const IoDelegate& io_delegate) {
+bool GenerateCppInterface(const CppOptions& options, const TypeNamespace& types,
+                          const AidlInterface& interface, const IoDelegate& io_delegate) {
   auto interface_src = BuildInterfaceSource(types, interface);
   auto client_src = BuildClientSource(types, interface);
   auto server_src = BuildServerSource(types, interface);
@@ -872,6 +949,48 @@
   return success;
 }
 
+bool GenerateCppParcel(const CppOptions& options, const cpp::TypeNamespace& types,
+                       const AidlStructuredParcelable& parcelable, const IoDelegate& io_delegate) {
+  auto header = BuildParcelHeader(types, parcelable);
+  auto source = BuildParcelSource(types, parcelable);
+
+  if (!header || !source) {
+    return false;
+  }
+
+  if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(), parcelable.GetSplitPackage())) {
+    LOG(ERROR) << "Failed to create directory structure for headers.";
+  }
+
+  const string header_path =
+      options.OutputHeaderDir() + OS_PATH_SEPARATOR + HeaderFile(parcelable, ClassNames::BASE);
+  unique_ptr<CodeWriter> header_writer(io_delegate.GetCodeWriter(header_path));
+  header->Write(header_writer.get());
+  CHECK(header_writer->Close());
+
+  unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(options.OutputCppFilePath());
+  source->Write(source_writer.get());
+  CHECK(source_writer->Close());
+
+  return true;
+}
+
+bool GenerateCpp(const CppOptions& options, const TypeNamespace& types,
+                 const AidlDefinedType& defined_type, const IoDelegate& io_delegate) {
+  const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable();
+  if (parcelable != nullptr) {
+    return GenerateCppParcel(options, types, *parcelable, io_delegate);
+  }
+
+  const AidlInterface* interface = defined_type.AsInterface();
+  if (interface != nullptr) {
+    return GenerateCppInterface(options, types, *interface, io_delegate);
+  }
+
+  CHECK(false) << "Unrecognized type sent for cpp generation.";
+  return false;
+}
+
 }  // namespace cpp
 }  // namespace aidl
 }  // namespace android
diff --git a/generate_cpp.h b/generate_cpp.h
index 1ffc681..2aa8341 100644
--- a/generate_cpp.h
+++ b/generate_cpp.h
@@ -29,10 +29,8 @@
 namespace aidl {
 namespace cpp {
 
-bool GenerateCpp(const CppOptions& options,
-                 const cpp::TypeNamespace& types,
-                 const AidlInterface& parsed_doc,
-                 const IoDelegate& io_delegate);
+bool GenerateCpp(const CppOptions& options, const cpp::TypeNamespace& types,
+                 const AidlDefinedType& parsed_doc, const IoDelegate& io_delegate);
 
 // These roughly correspond to the various class names in the C++ hierarchy:
 enum class ClassNames {
@@ -45,7 +43,7 @@
 // Generate the relative path to a header file.  If |use_os_sep| we'll use the
 // operating system specific path separator rather than C++'s expected '/' when
 // including headers.
-std::string HeaderFile(const AidlInterface& interface, ClassNames class_type,
+std::string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type,
                        bool use_os_sep = true);
 
 namespace internals {
@@ -61,6 +59,11 @@
                                             const AidlInterface& parsed_doc);
 std::unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
                                                const AidlInterface& parsed_doc);
+
+std::unique_ptr<Document> BuildParcelHeader(const TypeNamespace& types,
+                                            const AidlStructuredParcelable& parsed_doc);
+std::unique_ptr<Document> BuildParcelSource(const TypeNamespace& types,
+                                            const AidlStructuredParcelable& parsed_doc);
 }
 }  // namespace cpp
 }  // namespace aidl
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index 209f173..1e15f6b 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -1286,10 +1286,10 @@
     types_.Init();
   }
 
-  unique_ptr<AidlInterface> Parse() {
+  unique_ptr<AidlInterface> ParseInterface() {
     io_delegate_.SetFileContents(file_path_, file_contents_);
 
-    unique_ptr<AidlInterface> ret;
+    unique_ptr<AidlDefinedType> ret;
     std::vector<std::unique_ptr<AidlImport>> imports;
     AidlError err = ::android::aidl::internals::load_and_validate_aidl(
         {},  // no preprocessed files
@@ -1301,10 +1301,15 @@
         &ret,
         &imports);
 
-    if (err != AidlError::OK)
+    if (err != AidlError::OK) {
       return nullptr;
+    }
 
-    return ret;
+    if (ret->AsInterface() == nullptr) {
+      return nullptr;
+    }
+
+    return unique_ptr<AidlInterface>(static_cast<AidlInterface*>(ret.release()));
   }
 
   void Compare(Document* doc, const char* expected) {
@@ -1338,21 +1343,21 @@
 };
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientHeader) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   unique_ptr<Document> doc = internals::BuildClientHeader(types_, *interface);
   Compare(doc.get(), kExpectedComplexTypeClientHeaderOutput);
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSource) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   unique_ptr<Document> doc = internals::BuildClientSource(types_, *interface);
   Compare(doc.get(), kExpectedComplexTypeClientSourceOutput);
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSourceWithTrace) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   interface->SetGenerateTraces(true);
   unique_ptr<Document> doc = internals::BuildClientSource(types_, *interface);
@@ -1360,21 +1365,21 @@
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerHeader) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   unique_ptr<Document> doc = internals::BuildServerHeader(types_, *interface);
   Compare(doc.get(), kExpectedComplexTypeServerHeaderOutput);
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSource) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   unique_ptr<Document> doc = internals::BuildServerSource(types_, *interface);
   Compare(doc.get(), kExpectedComplexTypeServerSourceOutput);
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSourceWithTrace) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   interface->SetGenerateTraces(true);
   unique_ptr<Document> doc = internals::BuildServerSource(types_, *interface);
@@ -1382,14 +1387,14 @@
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceHeader) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   unique_ptr<Document> doc = internals::BuildInterfaceHeader(types_, *interface);
   Compare(doc.get(), kExpectedComplexTypeInterfaceHeaderOutput);
 }
 
 TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceSource) {
-  unique_ptr<AidlInterface> interface = Parse();
+  unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   unique_ptr<Document> doc = internals::BuildInterfaceSource(types_, *interface);
   Compare(doc.get(), kExpectedComplexTypeInterfaceSourceOutput);
@@ -1427,14 +1432,14 @@
 
 TEST_F(IoErrorHandlingTest, GenerateCorrectlyAbsentErrors) {
   // Confirm that this is working correctly without I/O problems.
-  const unique_ptr<AidlInterface> interface = Parse();
+  const unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
   ASSERT_TRUE(GenerateCpp(*options_, types_, *interface, io_delegate_));
 }
 
 TEST_F(IoErrorHandlingTest, HandlesBadHeaderWrite) {
   using namespace test_io_handling;
-  const unique_ptr<AidlInterface> interface = Parse();
+  const unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
 
   // Simulate issues closing the interface header.
@@ -1451,7 +1456,7 @@
 
 TEST_F(IoErrorHandlingTest, HandlesBadCppWrite) {
   using test_io_handling::kOutputPath;
-  const unique_ptr<AidlInterface> interface = Parse();
+  const unique_ptr<AidlInterface> interface = ParseInterface();
   ASSERT_NE(interface, nullptr);
 
   // Simulate issues closing the cpp file.
diff --git a/generate_java.cpp b/generate_java.cpp
index afa188a..1ca285b 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -16,10 +16,11 @@
 
 #include "generate_java.h"
 
-#include <memory>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <memory>
+#include <sstream>
 
 #include <android-base/stringprintf.h>
 
@@ -54,16 +55,13 @@
 
 namespace java {
 
-int generate_java(const string& filename, const string& originalSrc,
-                  AidlInterface* iface, JavaTypeNamespace* types,
-                  const IoDelegate& io_delegate, const JavaOptions& options) {
+int generate_java_interface(const string& filename, const string& original_src,
+                            const AidlInterface* iface, JavaTypeNamespace* types,
+                            const IoDelegate& io_delegate, const JavaOptions& options) {
   Class* cl = generate_binder_interface_class(iface, types, options);
 
-  Document* document = new Document(
-      "" /* no comment */,
-      iface->GetPackage(),
-      originalSrc,
-      unique_ptr<Class>(cl));
+  Document* document =
+      new Document("" /* no comment */, iface->GetPackage(), original_src, unique_ptr<Class>(cl));
 
   CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
   document->Write(code_writer.get());
@@ -71,6 +69,106 @@
   return 0;
 }
 
+int generate_java_parcel(const std::string& filename, const std::string& original_src,
+                         const AidlStructuredParcelable* parcel, JavaTypeNamespace* types,
+                         const IoDelegate& io_delegate, const JavaOptions& options) {
+  Class* cl = generate_parcel_class(parcel, types, options);
+
+  Document* document =
+      new Document("" /* no comment */, parcel->GetPackage(), original_src, unique_ptr<Class>(cl));
+
+  CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
+  document->Write(code_writer.get());
+
+  return 0;
+}
+
+int generate_java(const std::string& filename, const std::string& original_src,
+                  const AidlDefinedType* defined_type, JavaTypeNamespace* types,
+                  const IoDelegate& io_delegate, const JavaOptions& options) {
+  const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable();
+  if (parcelable != nullptr) {
+    return generate_java_parcel(filename, original_src, parcelable, types, io_delegate, options);
+  }
+
+  const AidlInterface* interface = defined_type->AsInterface();
+  if (interface != nullptr) {
+    return generate_java_interface(filename, original_src, interface, types, io_delegate, options);
+  }
+
+  CHECK(false) << "Unrecognized type sent for cpp generation.";
+  return false;
+}
+
+android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
+                                                  java::JavaTypeNamespace* types,
+                                                  const JavaOptions& options) {
+  const ParcelType* parcelType = parcel->GetLanguageType<ParcelType>();
+
+  Class* parcel_class = new Class;
+  parcel_class->comment = parcel->GetComments();
+  parcel_class->modifiers = PUBLIC;
+  parcel_class->what = Class::CLASS;
+  parcel_class->type = parcelType;
+
+  for (const auto& variable : parcel->GetFields()) {
+    const Type* type = variable->GetType().GetLanguageType<Type>();
+    Variable* variable_element =
+        new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
+    parcel_class->elements.push_back(new Field(PUBLIC, variable_element));
+  }
+
+  std::ostringstream out;
+  out << "public static final android.os.Parcelable.Creator<" << parcel->GetName() << "> CREATOR = "
+      << "new android.os.Parcelable.Creator<" << parcel->GetName() << ">() {\n";
+  out << "  public " << parcel->GetName()
+      << " createFromParcel(android.os.Parcel _aidl_source) {\n";
+  out << "    " << parcel->GetName() << " _aidl_out = new " << parcel->GetName() << "();\n";
+  out << "    _aidl_out.readFromParcel(_aidl_source);\n";
+  out << "    return _aidl_out;\n";
+  out << "  }\n";
+  out << "  public " << parcel->GetName() << "[] newArray(int _aidl_size) {\n";
+  out << "    return new " << parcel->GetName() << "[_aidl_size];\n";
+  out << "  }\n";
+  out << "};\n";
+  parcel_class->elements.push_back(new LiteralClassElement(out.str()));
+
+  Variable* flag_variable = new Variable(new Type(types, "int", 0, false, false), "_aidl_flag");
+  Variable* parcel_variable =
+      new Variable(new Type(types, "android.os.Parcel", 0, false, false), "_aidl_parcel");
+
+  Method* write_method = new Method;
+  write_method->modifiers = PUBLIC;
+  write_method->returnType = new Type(types, "void", 0, false, false);
+  write_method->name = "writeToParcel";
+  write_method->parameters.push_back(parcel_variable);
+  write_method->parameters.push_back(flag_variable);
+  write_method->statements = new StatementBlock();
+  for (const auto& variable : parcel->GetFields()) {
+    const Type* type = variable->GetType().GetLanguageType<Type>();
+    Variable* variable_element =
+        new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
+    type->WriteToParcel(write_method->statements, variable_element, parcel_variable, 0 /*flags*/);
+  }
+  parcel_class->elements.push_back(write_method);
+
+  Method* read_method = new Method;
+  read_method->modifiers = PUBLIC;
+  read_method->returnType = new Type(types, "void", 0, false, false);
+  read_method->name = "readFromParcel";
+  read_method->parameters.push_back(parcel_variable);
+  read_method->statements = new StatementBlock();
+  for (const auto& variable : parcel->GetFields()) {
+    const Type* type = variable->GetType().GetLanguageType<Type>();
+    Variable* variable_element =
+        new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
+    type->CreateFromParcel(read_method->statements, variable_element, parcel_variable, 0 /*flags*/);
+  }
+  parcel_class->elements.push_back(read_method);
+
+  return parcel_class;
+}
+
 }  // namespace java
 }  // namespace android
 }  // namespace aidl
diff --git a/generate_java.h b/generate_java.h
index 59fed62..680a199 100644
--- a/generate_java.h
+++ b/generate_java.h
@@ -32,14 +32,18 @@
 
 class JavaTypeNamespace;
 
-int generate_java(const std::string& filename, const std::string& originalSrc,
-                  AidlInterface* iface, java::JavaTypeNamespace* types,
+int generate_java(const std::string& filename, const std::string& original_src,
+                  const AidlDefinedType* iface, java::JavaTypeNamespace* types,
                   const IoDelegate& io_delegate, const JavaOptions& options);
 
 android::aidl::java::Class* generate_binder_interface_class(
     const AidlInterface* iface, java::JavaTypeNamespace* types,
     const JavaOptions& options);
 
+android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
+                                                  java::JavaTypeNamespace* types,
+                                                  const JavaOptions& options);
+
 }  // namespace java
 
 class VariableFactory {
diff --git a/tests/aidl_test_client.cpp b/tests/aidl_test_client.cpp
index 84c8183..8c06889 100644
--- a/tests/aidl_test_client.cpp
+++ b/tests/aidl_test_client.cpp
@@ -90,6 +90,8 @@
 
   if (!client_tests::ConfirmPersistableBundles(service)) return 1;
 
+  if (!client_tests::ConfirmStructuredParcelables(service)) return 1;
+
   if (!client_tests::ConfirmFileDescriptors(service)) return 1;
 
   if (!client_tests::ConfirmFileDescriptorArrays(service)) return 1;
diff --git a/tests/aidl_test_client_parcelables.cpp b/tests/aidl_test_client_parcelables.cpp
index 09e7f0a..66b66c0 100644
--- a/tests/aidl_test_client_parcelables.cpp
+++ b/tests/aidl_test_client_parcelables.cpp
@@ -145,6 +145,35 @@
   return true;
 }
 
+bool ConfirmStructuredParcelables(const sp<ITestService>& s) {
+  constexpr int kDesiredValue = 23;
+
+  StructuredParcelable parcelable;
+  parcelable.f = kDesiredValue;
+
+  s->FillOutStructuredParcelable(&parcelable);
+
+  if (parcelable.shouldContainThreeFs.size() != 3) {
+    cout << "shouldContainThreeFs is of length " << parcelable.shouldContainThreeFs.size() << endl;
+    return false;
+  }
+
+  for (int i = 0; i < 3; i++) {
+    if (parcelable.shouldContainThreeFs[i] != kDesiredValue) {
+      cout << "shouldContainThreeFs[" << i << "] is " << parcelable.shouldContainThreeFs[i]
+           << " but should be " << kDesiredValue << endl;
+      return false;
+    }
+  }
+
+  if (parcelable.shouldBeJerry != "Jerry") {
+    cout << "shouldBeJerry is not Jerry and is instead " << parcelable.shouldBeJerry << endl;
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace client
 }  // namespace tests
 }  // namespace aidl
diff --git a/tests/aidl_test_client_parcelables.h b/tests/aidl_test_client_parcelables.h
index 9616e02..168f6cd 100644
--- a/tests/aidl_test_client_parcelables.h
+++ b/tests/aidl_test_client_parcelables.h
@@ -29,6 +29,7 @@
 
 bool ConfirmSimpleParcelables(const sp<ITestService>& s);
 bool ConfirmPersistableBundles(const sp<ITestService>& s);
+bool ConfirmStructuredParcelables(const sp<ITestService>& s);
 
 }  // namespace client
 }  // namespace tests
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index c5e4bcd..8a64ebc 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -438,6 +438,13 @@
     return Status::ok();
   }
 
+  virtual ::android::binder::Status FillOutStructuredParcelable(
+      ::android::aidl::tests::StructuredParcelable* parcelable) {
+    parcelable->shouldBeJerry = "Jerry";
+    parcelable->shouldContainThreeFs = {parcelable->f, parcelable->f, parcelable->f};
+    return Status::ok();
+  }
+
  private:
   map<String16, sp<INamedCallback>> service_map_;
 };
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index 1f2ae8c..5fd962c 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -18,6 +18,7 @@
 
 import android.aidl.tests.INamedCallback;
 import android.aidl.tests.SimpleParcelable;
+import android.aidl.tests.StructuredParcelable;
 import android.os.PersistableBundle;
 
 interface ITestService {
@@ -113,4 +114,7 @@
       out @nullable @utf8InCpp List<String> repeated);
 
   @nullable INamedCallback GetCallback(boolean return_null);
+
+  // This is not a well designed API and should not be taken as an example
+  void FillOutStructuredParcelable(inout StructuredParcelable parcel);
 }
diff --git a/tests/android/aidl/tests/StructuredParcelable.aidl b/tests/android/aidl/tests/StructuredParcelable.aidl
new file mode 100644
index 0000000..bc23eb6
--- /dev/null
+++ b/tests/android/aidl/tests/StructuredParcelable.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * 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 android.aidl.tests;
+
+parcelable StructuredParcelable {
+    int[] shouldContainThreeFs;
+    int f;
+    @utf8InCpp String shouldBeJerry;
+}
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index 04ca2e9..18dd236 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -17,6 +17,7 @@
 package android.aidl.tests;
 
 import android.aidl.tests.SimpleParcelable;
+import android.aidl.tests.StructuredParcelable;
 import android.aidl.tests.TestFailException;
 import android.aidl.tests.TestLogger;
 import android.app.Activity;
@@ -699,6 +700,37 @@
         mLog.log("...UTF8 annotations work.");
     }
 
+    private void checkStructuredParcelable(ITestService service) throws TestFailException {
+      final int kDesiredFValue = 17;
+
+      StructuredParcelable parcelable = new StructuredParcelable();
+      parcelable.shouldContainThreeFs = new int[0];
+      parcelable.f = kDesiredFValue;
+      parcelable.shouldBeJerry = "";
+
+      try {
+        service.FillOutStructuredParcelable(parcelable);
+      } catch (RemoteException ex) {
+        mLog.log(ex.toString());
+        mLog.logAndThrow("Service failed to handle structured parcelable.");
+      }
+
+      if (parcelable.shouldContainThreeFs.length != 3) {
+        mLog.logAndThrow(
+            "shouldContainThreeFs is of length " + parcelable.shouldContainThreeFs.length);
+      }
+      for (int i = 0; i < 3; i++) {
+        if (parcelable.shouldContainThreeFs[i] != kDesiredFValue) {
+          mLog.logAndThrow("shouldContainThreeFs[" + i + "] is "
+              + parcelable.shouldContainThreeFs[i] + " but should be " + kDesiredFValue);
+        }
+      }
+
+      if (!parcelable.shouldBeJerry.equals("Jerry")) {
+        mLog.logAndThrow("shouldBeJerry should be 'Jerry' but is " + parcelable.shouldBeJerry);
+      }
+    }
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -715,6 +747,7 @@
           checkFileDescriptorPassing(service);
           checkServiceSpecificExceptions(service);
           checkUtf8Strings(service);
+          checkStructuredParcelable(service);
           new NullableTests(service, mLog).runTests();
 
           mLog.log(mSuccessSentinel);
diff --git a/type_cpp.cpp b/type_cpp.cpp
index 6159231..ead99f8 100644
--- a/type_cpp.cpp
+++ b/type_cpp.cpp
@@ -171,6 +171,12 @@
   DISALLOW_COPY_AND_ASSIGN(ByteType);
 };  // class PrimitiveType
 
+static string GetCppHeader(const AidlDefinedType& defined_type) {
+  vector<string> name = defined_type.GetSplitPackage();
+  name.push_back(defined_type.GetName());
+  return Join(name, '/') + ".h";
+}
+
 class BinderType : public Type {
  public:
   BinderType(const AidlInterface& interface, const std::string& src_file_name)
@@ -212,25 +218,16 @@
     return ret;
   }
 
-  static string GetCppHeader(const AidlInterface& interface) {
-    vector<string> name = interface.GetSplitPackage();
-    name.push_back(interface.GetName());
-    return Join(name, '/') + ".h";
-  }
-
   std::string write_cast_;
 };
 
 class NullableParcelableType : public Type {
  public:
-  NullableParcelableType(const AidlParcelable& parcelable,
+  NullableParcelableType(const AidlParcelable& parcelable, const std::string& cpp_header,
                          const std::string& src_file_name)
-      : Type(ValidatableType::KIND_PARCELABLE,
-             parcelable.GetPackage(), parcelable.GetName(),
-             {parcelable.GetCppHeader()}, GetCppName(parcelable),
-             "readParcelable", "writeNullableParcelable",
-             kNoArrayType, kNoNullableType,
-             src_file_name, parcelable.GetLine()) {}
+      : Type(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(),
+             {cpp_header}, GetCppName(parcelable), "readParcelable", "writeNullableParcelable",
+             kNoArrayType, kNoNullableType, src_file_name, parcelable.GetLine()) {}
   virtual ~NullableParcelableType() = default;
   bool CanBeOutParameter() const override { return true; }
 
@@ -243,20 +240,16 @@
 
 class ParcelableType : public Type {
  public:
-  ParcelableType(const AidlParcelable& parcelable,
+  ParcelableType(const AidlParcelable& parcelable, const std::string& cpp_header,
                  const std::string& src_file_name)
-      : Type(ValidatableType::KIND_PARCELABLE,
-             parcelable.GetPackage(), parcelable.GetName(),
-             {parcelable.GetCppHeader()}, GetCppName(parcelable),
-             "readParcelable", "writeParcelable",
-             new CppArrayType(
-                 ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(),
-                 parcelable.GetName(), parcelable.GetCppHeader(),
-                 GetCppName(parcelable), GetCppName(parcelable),
-                 "readParcelableVector", "writeParcelableVector", false,
-                 src_file_name),
-             new NullableParcelableType(parcelable, src_file_name),
-             src_file_name, parcelable.GetLine()) {}
+      : Type(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(),
+             {cpp_header}, GetCppName(parcelable), "readParcelable", "writeParcelable",
+             new CppArrayType(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(),
+                              parcelable.GetName(), cpp_header, GetCppName(parcelable),
+                              GetCppName(parcelable), "readParcelableVector",
+                              "writeParcelableVector", false, src_file_name),
+             new NullableParcelableType(parcelable, cpp_header, src_file_name), src_file_name,
+             parcelable.GetLine()) {}
   virtual ~ParcelableType() = default;
   bool CanBeOutParameter() const override { return true; }
 
@@ -515,12 +508,15 @@
 
 bool TypeNamespace::AddParcelableType(const AidlParcelable& p,
                                       const string& filename) {
-  if (p.GetCppHeader().empty()) {
+  const std::string cpp_header = p.AsStructuredParcelable() ? GetCppHeader(p) : p.GetCppHeader();
+
+  if (cpp_header.empty()) {
     LOG(ERROR) << "Parcelable " << p.GetCanonicalName()
                << " has no C++ header defined.";
     return false;
   }
-  Add(new ParcelableType(p, filename));
+
+  Add(new ParcelableType(p, cpp_header, filename));
   return true;
 }
 
@@ -578,10 +574,9 @@
   return true;
 }
 
-const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a,
-    int arg_index,
-    const std::string& filename,
-    const AidlInterface& interface) const {
+const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index,
+                                                 const std::string& filename,
+                                                 const AidlDefinedType& context) const {
   const string error_prefix = StringPrintf(
       "In file %s line %d parameter %s (%d):\n    ",
       filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
@@ -593,8 +588,7 @@
     return nullptr;
   }
 
-  return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename,
-                                                    interface);
+  return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename, context);
 }
 
 }  // namespace cpp
diff --git a/type_cpp.h b/type_cpp.h
index 0a6a4a9..65c9886 100644
--- a/type_cpp.h
+++ b/type_cpp.h
@@ -102,10 +102,9 @@
                   const std::string& value_type_name) override;
 
   bool IsValidPackage(const std::string& package) const override;
-  const ValidatableType* GetArgType(const AidlArgument& a,
-                             int arg_index,
-                             const std::string& filename,
-                             const AidlInterface& interface) const override;
+  const ValidatableType* GetArgType(const AidlArgument& a, int arg_index,
+                                    const std::string& filename,
+                                    const AidlDefinedType& context) const override;
 
   const Type* VoidType() const { return void_type_; }
   const Type* IBinderType() const { return ibinder_type_; }
diff --git a/type_namespace.cpp b/type_namespace.cpp
index d3f4aaf..06695c6 100644
--- a/type_namespace.cpp
+++ b/type_namespace.cpp
@@ -97,12 +97,11 @@
   return true;
 }
 
-const ValidatableType* TypeNamespace::GetReturnType(
-    const AidlType& raw_type, const string& filename,
-    const AidlInterface& interface) const {
+const ValidatableType* TypeNamespace::GetReturnType(const AidlType& raw_type,
+                                                    const string& filename,
+                                                    const AidlDefinedType& context) const {
   string error_msg;
-  const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg,
-                                                          interface);
+  const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg, context);
   if (return_type == nullptr) {
     LOG(ERROR) << StringPrintf("In file %s line %d return type %s:\n    ",
                                filename.c_str(), raw_type.GetLine(),
@@ -114,17 +113,16 @@
   return return_type;
 }
 
-const ValidatableType* TypeNamespace::GetArgType(
-    const AidlArgument& a, int arg_index, const string& filename,
-    const AidlInterface& interface) const {
+const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index,
+                                                 const string& filename,
+                                                 const AidlDefinedType& context) const {
   string error_prefix = StringPrintf(
       "In file %s line %d parameter %s (argument %d):\n    ",
       filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
 
   // check the arg type
   string error_msg;
-  const ValidatableType* t = GetValidatableType(a.GetType(), &error_msg,
-                                                interface);
+  const ValidatableType* t = GetValidatableType(a.GetType(), &error_msg, context);
   if (t == nullptr) {
     LOG(ERROR) << error_prefix << error_msg;
     return nullptr;
diff --git a/type_namespace.h b/type_namespace.h
index 7defd24..315641e 100644
--- a/type_namespace.h
+++ b/type_namespace.h
@@ -97,6 +97,7 @@
   // Load this TypeNamespace with user defined types.
   virtual bool AddParcelableType(const AidlParcelable& p,
                                  const std::string& filename) = 0;
+
   virtual bool AddBinderType(const AidlInterface& b,
                              const std::string& filename) = 0;
   // Add a container type to this namespace.  Returns false only
@@ -111,30 +112,25 @@
 
   // Returns a pointer to a type corresponding to |raw_type| or nullptr
   // if this is an invalid return type.
-  virtual const ValidatableType* GetReturnType(
-      const AidlType& raw_type,
-      const std::string& filename,
-      const AidlInterface& interface) const;
+  virtual const ValidatableType* GetReturnType(const AidlType& raw_type,
+                                               const std::string& filename,
+                                               const AidlDefinedType& context) const;
 
   // Returns a pointer to a type corresponding to |a| or nullptr if |a|
   // has an invalid argument type.
-  virtual const ValidatableType* GetArgType(
-      const AidlArgument& a,
-      int arg_index,
-      const std::string& filename,
-      const AidlInterface& interface) const;
+  virtual const ValidatableType* GetArgType(const AidlArgument& a, int arg_index,
+                                            const std::string& filename,
+                                            const AidlDefinedType& context) const;
 
-  // Returns a pointer to a type corresponding to |interface|.
-  virtual const ValidatableType* GetInterfaceType(
-      const AidlInterface& interface) const = 0;
+  // Returns a pointer to a type corresponding to |defined_type|.
+  virtual const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const = 0;
 
  protected:
   TypeNamespace() = default;
   virtual ~TypeNamespace() = default;
 
-  virtual const ValidatableType* GetValidatableType(
-      const AidlType& type, std::string* error_msg,
-      const AidlInterface& interface) const = 0;
+  virtual const ValidatableType* GetValidatableType(const AidlType& type, std::string* error_msg,
+                                                    const AidlDefinedType& context) const = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
@@ -160,9 +156,8 @@
   bool HasImportType(const AidlImport& import) const override {
     return HasTypeByCanonicalName(import.GetNeededClass());
   }
-  const ValidatableType* GetInterfaceType(
-      const AidlInterface& interface) const override {
-    return FindTypeByCanonicalName(interface.GetCanonicalName());
+  const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const override {
+    return FindTypeByCanonicalName(defined_type.GetCanonicalName());
   }
 
   bool MaybeAddContainerType(const AidlType& aidl_type) override;
@@ -185,9 +180,8 @@
   // Returns true if this is a container type, rather than a normal type.
   bool IsContainerType(const std::string& type_name) const;
 
-  const ValidatableType* GetValidatableType(
-      const AidlType& type, std::string* error_msg,
-      const AidlInterface& interface) const override;
+  const ValidatableType* GetValidatableType(const AidlType& type, std::string* error_msg,
+                                            const AidlDefinedType& context) const override;
 
   std::vector<std::unique_ptr<const T>> types_;
 
@@ -383,10 +377,9 @@
   return false;
 }
 
-template<typename T>
+template <typename T>
 const ValidatableType* LanguageTypeNamespace<T>::GetValidatableType(
-    const AidlType& aidl_type, std::string* error_msg,
-    const AidlInterface& interface) const {
+    const AidlType& aidl_type, std::string* error_msg, const AidlDefinedType& context) const {
   using android::base::StringPrintf;
 
   const ValidatableType* type = Find(aidl_type);
@@ -428,8 +421,8 @@
     utf8InCpp = false;
   } else if (aidl_type.GetName() == "String" ||
              aidl_type.GetName() == "java.lang.String") {
-    utf8 = utf8 || interface.IsUtf8();
-    utf8InCpp = utf8InCpp || interface.IsUtf8InCpp();
+    utf8 = utf8 || context.IsUtf8();
+    utf8InCpp = utf8InCpp || context.IsUtf8InCpp();
   } else if (utf8 || utf8InCpp) {
     const char* annotation_literal =
         (utf8) ? kUtf8Annotation : kUtf8InCppAnnotation;
@@ -469,7 +462,7 @@
     }
   }
 
-  if (interface.IsNullable()) {
+  if (context.IsNullable()) {
     const ValidatableType* nullableType = type->NullableType();
 
     if (nullableType) {