[Java hidl-gen] Fix multi-dimensional arrays (used within structures, not

as method arguments).

Bug: 31438033
Change-Id: I8e29ae8eca2a9ef8a320e37ca0bb79dcfa8a9b9a
diff --git a/ArrayType.cpp b/ArrayType.cpp
index 2ca27ec..71f97a3 100644
--- a/ArrayType.cpp
+++ b/ArrayType.cpp
@@ -51,8 +51,19 @@
     }
 }
 
-std::string ArrayType::getJavaType() const {
-    return mElementType->getJavaType() + "[]";
+std::string ArrayType::getJavaType(
+        std::string *extra, bool forInitializer) const {
+    std::string baseExtra;
+    const std::string base =
+        mElementType->getJavaType(&baseExtra, forInitializer);
+
+    *extra = "[";
+    if (forInitializer) {
+        (*extra) += mDimension;
+    }
+    (*extra) += "]" + baseExtra;
+
+    return base;
 }
 
 void ArrayType::emitReaderWriter(
@@ -185,16 +196,18 @@
         const std::string &parcelObj,
         const std::string &argName,
         bool isReader) const {
+    std::string extra;
+
     if (mElementType->isCompoundType()) {
         if (isReader) {
-            out << mElementType->getJavaType()
+            out << mElementType->getJavaType(&extra)
                 << ".readArrayFromParcel("
                 << parcelObj
                 << ", "
                 << mDimension
                 << ");\n";
         } else {
-            out << mElementType->getJavaType()
+            out << mElementType->getJavaType(&extra)
                 << ".writeArrayToParcel("
                 << parcelObj
                 << ", "
@@ -218,26 +231,41 @@
 
 void ArrayType::emitJavaFieldInitializer(
         Formatter &out, const std::string &fieldName) const {
+    std::string extra;
+    std::string typeName = getJavaType(&extra, false /* forInitializer */);
+
+    std::string extraInit;
+    getJavaType(&extraInit, true /* forInitializer */);
+
     out << "final "
-        << mElementType->getJavaType()
-        << "[] "
+        << typeName
+        << extra
+        << " "
         << fieldName
         << " = new "
-        << mElementType->getJavaType()
-        << "["
-        << mDimension
-        << "];\n";
+        << typeName
+        << extraInit
+        << ";\n";
 }
 
 void ArrayType::emitJavaFieldReaderWriter(
         Formatter &out,
+        size_t depth,
         const std::string &blobName,
         const std::string &fieldName,
         const std::string &offset,
         bool isReader) const {
-    out << "for (int _hidl_index = 0; _hidl_index < "
+    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
+
+    out << "for (int "
+        << iteratorName
+        << " = 0; "
+        << iteratorName
+        << " < "
         << mDimension
-        << "; ++_hidl_index) {\n";
+        << "; ++"
+        << iteratorName
+        << ") {\n";
 
     out.indent();
 
@@ -246,9 +274,10 @@
 
     mElementType->emitJavaFieldReaderWriter(
             out,
+            depth + 1,
             blobName,
-            fieldName + "[_hidl_index]",
-            offset + " + _hidl_index * " + std::to_string(elementSize),
+            fieldName + "[" + iteratorName + "]",
+            offset + " + " + iteratorName + " * " + std::to_string(elementSize),
             isReader);
 
     out.unindent();
diff --git a/ArrayType.h b/ArrayType.h
index 7a39716..3b2faf9 100644
--- a/ArrayType.h
+++ b/ArrayType.h
@@ -33,7 +33,8 @@
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
 
     void emitReaderWriter(
             Formatter &out,
@@ -68,6 +69,7 @@
 
     void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 8a692c1..5c702c2 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -82,7 +82,9 @@
     }
 }
 
-std::string CompoundType::getJavaType() const {
+std::string CompoundType::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
+    extra->clear();
     return fullJavaName();
 }
 
@@ -208,6 +210,7 @@
 
 void CompoundType::emitJavaFieldReaderWriter(
         Formatter &out,
+        size_t /* depth */,
         const std::string &blobName,
         const std::string &fieldName,
         const std::string &offset,
@@ -389,7 +392,13 @@
     out << "HwBlob _hidl_blob = parcel.readBuffer();\n\n";
 
     VectorType::EmitJavaFieldReaderWriterForElementType(
-            out, this, "_hidl_blob", "_hidl_vec", "0", true /* isReader */);
+            out,
+            0 /* depth */,
+            this,
+            "_hidl_blob",
+            "_hidl_vec",
+            "0",
+            true /* isReader */);
 
     out << "\nreturn _hidl_vec.toArray(new "
         << localName()
@@ -418,6 +427,7 @@
 
         field->type().emitJavaFieldReaderWriter(
                 out,
+                0 /* depth */,
                 "_hidl_blob",
                 field->name(),
                 "_hidl_offset + " + std::to_string(offset),
@@ -495,7 +505,13 @@
     out << "HwBlob _hidl_blob = new HwBlob(24 /* sizeof(hidl_vec<T>) */);\n";
 
     VectorType::EmitJavaFieldReaderWriterForElementType(
-            out, this, "_hidl_blob", "_hidl_vec", "0", false /* isReader */);
+            out,
+            0 /* depth */,
+            this,
+            "_hidl_blob",
+            "_hidl_vec",
+            "0",
+            false /* isReader */);
 
     out << "\nparcel.writeBuffer(_hidl_blob);\n";
 
@@ -522,6 +538,7 @@
 
         field->type().emitJavaFieldReaderWriter(
                 out,
+                0 /* depth */,
                 "_hidl_blob",
                 field->name(),
                 "_hidl_offset + " + std::to_string(offset),
diff --git a/CompoundType.h b/CompoundType.h
index b59bbd2..b6b2d14 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -42,7 +42,8 @@
                            std::string *extra,
                            bool specifyNamespaces) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
 
     void emitReaderWriter(
             Formatter &out,
@@ -75,6 +76,7 @@
 
     void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
diff --git a/EnumType.cpp b/EnumType.cpp
index d4e4408..2f01521 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -60,8 +60,10 @@
     return specifyNamespaces ? fullName() : partialCppName();
 }
 
-std::string EnumType::getJavaType() const {
-    return mStorageType->resolveToScalarType()->getJavaType();
+std::string EnumType::getJavaType(
+        std::string *extra, bool forInitializer) const {
+    return mStorageType->resolveToScalarType()->getJavaType(
+            extra, forInitializer);
 }
 
 std::string EnumType::getJavaSuffix() const {
@@ -94,12 +96,13 @@
 
 void EnumType::emitJavaFieldReaderWriter(
         Formatter &out,
+        size_t depth,
         const std::string &blobName,
         const std::string &fieldName,
         const std::string &offset,
         bool isReader) const {
     return mStorageType->emitJavaFieldReaderWriter(
-            out, blobName, fieldName, offset, isReader);
+            out, depth, blobName, fieldName, offset, isReader);
 }
 
 status_t EnumType::emitTypeDeclarations(Formatter &out) const {
@@ -187,7 +190,9 @@
 
     out.indent();
 
-    const std::string typeName = scalarType->getJavaType();
+    std::string extra;  // unused, because ScalarType leaves this empty.
+    const std::string typeName =
+        scalarType->getJavaType(&extra, false /* forInitializer */);
 
     std::vector<const EnumType *> chain;
     getTypeChain(&chain);
diff --git a/EnumType.h b/EnumType.h
index 3beabbb..35a07f6 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -43,7 +43,9 @@
                            std::string *extra,
                            bool specifyNamespaces) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
+
     std::string getJavaSuffix() const override;
 
     std::string getJavaWrapperType() const override;
@@ -58,6 +60,7 @@
 
     void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
diff --git a/GenericBinder.cpp b/GenericBinder.cpp
index 8f85ad7..bf7f99e 100644
--- a/GenericBinder.cpp
+++ b/GenericBinder.cpp
@@ -51,7 +51,9 @@
     }
 }
 
-std::string GenericBinder::getJavaType() const {
+std::string GenericBinder::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
+    extra->clear();
     return "IHwBinder";
 }
 
diff --git a/GenericBinder.h b/GenericBinder.h
index 536e8c4..db7c6cc 100644
--- a/GenericBinder.h
+++ b/GenericBinder.h
@@ -29,10 +29,13 @@
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
-    std::string getJavaType() const override;
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
+
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
 
     void emitReaderWriter(
             Formatter &out,
diff --git a/HandleType.cpp b/HandleType.cpp
index 1ab2e69..f36aaef 100644
--- a/HandleType.cpp
+++ b/HandleType.cpp
@@ -39,11 +39,6 @@
     return "const " + base + "*";
 }
 
-std::string HandleType::getJavaType() const {
-    CHECK(!"Should not be here");
-    return std::string();
-}
-
 void HandleType::emitReaderWriter(
         Formatter &out,
         const std::string &name,
diff --git a/HandleType.h b/HandleType.h
index 94b040d..2283229 100644
--- a/HandleType.h
+++ b/HandleType.h
@@ -27,10 +27,10 @@
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
-    std::string getJavaType() const override;
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
 
     void emitReaderWriter(
             Formatter &out,
diff --git a/Interface.cpp b/Interface.cpp
index 66abf8b..10f6505 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -82,7 +82,9 @@
     }
 }
 
-std::string Interface::getJavaType() const {
+std::string Interface::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
+    extra->clear();
     return fullJavaName();
 }
 
diff --git a/Interface.h b/Interface.h
index 3e2a22a..4adfbae 100644
--- a/Interface.h
+++ b/Interface.h
@@ -46,11 +46,13 @@
 
     std::string getBaseName() const;
 
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
 
     void emitReaderWriter(
             Formatter &out,
diff --git a/Method.cpp b/Method.cpp
index c051a77..7d7717a 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -123,10 +123,10 @@
         }
 
         std::string extra;
-        out += arg->type().getJavaType();
+        out += arg->type().getJavaType(&extra);
+        out += extra;
         out += " ";
         out += arg->name();
-        out += extra;
 
         first = false;
     }
diff --git a/PredefinedType.cpp b/PredefinedType.cpp
index ad9698c..30e0741 100644
--- a/PredefinedType.cpp
+++ b/PredefinedType.cpp
@@ -48,11 +48,6 @@
     }
 }
 
-std::string PredefinedType::getJavaType() const {
-    CHECK(!"Should not be here");
-    return std::string();
-}
-
 void PredefinedType::emitReaderWriter(
         Formatter &out,
         const std::string &name,
diff --git a/PredefinedType.h b/PredefinedType.h
index 84c9441..8fdd67f 100644
--- a/PredefinedType.h
+++ b/PredefinedType.h
@@ -26,10 +26,11 @@
     PredefinedType(const char *name);
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
-    std::string getJavaType() const override;
+
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
 
     void emitReaderWriter(
             Formatter &out,
diff --git a/ScalarType.cpp b/ScalarType.cpp
index b2b869e..2bff4ab 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -58,7 +58,8 @@
     return kName[mKind];
 }
 
-std::string ScalarType::getJavaType() const {
+std::string ScalarType::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
     static const char *const kName[] = {
         "boolean",
         "long",
@@ -74,6 +75,7 @@
         "double"
     };
 
+    extra->clear();
     return kName[mKind];
 }
 
@@ -184,6 +186,7 @@
 
 void ScalarType::emitJavaFieldReaderWriter(
         Formatter &out,
+        size_t /* depth */,
         const std::string &blobName,
         const std::string &fieldName,
         const std::string &offset,
diff --git a/ScalarType.h b/ScalarType.h
index 7f89cc9..9554e34 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -46,11 +46,14 @@
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
+
     std::string getJavaWrapperType() const override;
     std::string getJavaSuffix() const override;
 
@@ -73,6 +76,7 @@
 
     void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
diff --git a/Scope.cpp b/Scope.cpp
index 915934c..e7a48c6 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -94,11 +94,6 @@
     }
 }
 
-std::string Scope::getJavaType() const {
-    CHECK(!"Should not be here");
-    return std::string();
-}
-
 status_t Scope::emitTypeDeclarations(Formatter &out) const {
     for (size_t i = 0; i < mTypes.size(); ++i) {
         status_t err = mTypes[i]->emitTypeDeclarations(out);
diff --git a/Scope.h b/Scope.h
index 39748be..f6369c6 100644
--- a/Scope.h
+++ b/Scope.h
@@ -44,8 +44,6 @@
 
     std::string pickUniqueAnonymousName() const;
 
-    std::string getJavaType() const override;
-
     status_t emitTypeDeclarations(Formatter &out) const override;
 
     status_t emitJavaTypeDeclarations(
diff --git a/StringType.cpp b/StringType.cpp
index d5dba42..afaba82 100644
--- a/StringType.cpp
+++ b/StringType.cpp
@@ -47,7 +47,9 @@
     }
 }
 
-std::string StringType::getJavaType() const {
+std::string StringType::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
+    extra->clear();
     return "String";
 }
 
@@ -149,6 +151,7 @@
 
 void StringType::emitJavaFieldReaderWriter(
         Formatter &out,
+        size_t /* depth */,
         const std::string &blobName,
         const std::string &fieldName,
         const std::string &offset,
diff --git a/StringType.h b/StringType.h
index 9062d90..f66ea09 100644
--- a/StringType.h
+++ b/StringType.h
@@ -27,11 +27,14 @@
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool /* forInitializer */) const override;
+
     std::string getJavaSuffix() const override;
 
     void emitReaderWriter(
@@ -59,6 +62,7 @@
 
     void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
diff --git a/Type.cpp b/Type.cpp
index 8abffd6..b09f8d3 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -73,8 +73,16 @@
     return std::string();
 }
 
+std::string Type::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
+    CHECK(!"Should not be here");
+    extra->clear();
+    return std::string();
+}
+
 std::string Type::getJavaWrapperType() const {
-    return getJavaType();
+    std::string extra;
+    return getJavaType(&extra);
 }
 
 std::string Type::getJavaSuffix() const {
@@ -123,7 +131,8 @@
 void Type::emitJavaFieldInitializer(
         Formatter &out,
         const std::string &fieldName) const {
-    out << getJavaType()
+    std::string extra;
+    out << getJavaType(&extra)
         << " "
         << fieldName
         << ";\n";
@@ -131,6 +140,7 @@
 
 void Type::emitJavaFieldReaderWriter(
         Formatter &,
+        size_t,
         const std::string &,
         const std::string &,
         const std::string &,
diff --git a/Type.h b/Type.h
index 3e276c2..5c51fa9 100644
--- a/Type.h
+++ b/Type.h
@@ -70,15 +70,21 @@
     virtual void addNamedTypesToSet(std::set<const FQName> &set) const = 0;
 
     // Convenience, gets StorageMode_Stack type.
-    std::string getCppType(std::string *extra,
-                           bool specifyNamespaces = true) const;
+    std::string getCppType(
+            std::string *extra, bool specifyNamespaces = true) const;
 
-    std::string getCppResultType(std::string *extra,
-                                 bool specifyNamespaces = true) const;
-    std::string getCppArgumentType(std::string *extra,
-                                   bool specifyNamespaces = true) const;
+    std::string getCppResultType(
+            std::string *extra, bool specifyNamespaces = true) const;
 
-    virtual std::string getJavaType() const = 0;
+    std::string getCppArgumentType(
+            std::string *extra, bool specifyNamespaces = true) const;
+
+    // For an array type, "extra" accumulates dimensionality information,
+    // if forInitializer == true, actual dimensions are included, i.e. [3][5],
+    // otherwise (and by default), they are omitted, i.e. [][].
+    virtual std::string getJavaType(
+            std::string *extra, bool forInitializer = false) const;
+
     virtual std::string getJavaWrapperType() const;
     virtual std::string getJavaSuffix() const;
 
@@ -120,6 +126,7 @@
 
     virtual void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
diff --git a/TypeDef.cpp b/TypeDef.cpp
index 34cd124..731e07b 100644
--- a/TypeDef.cpp
+++ b/TypeDef.cpp
@@ -52,11 +52,6 @@
     return true;
 }
 
-std::string TypeDef::getJavaType() const {
-    CHECK(!"Should not be here");
-    return std::string();
-}
-
 bool TypeDef::needsEmbeddedReadWrite() const {
     CHECK(!"Should not be here");
     return false;
diff --git a/TypeDef.h b/TypeDef.h
index 5a59135..28fa0ff 100644
--- a/TypeDef.h
+++ b/TypeDef.h
@@ -34,9 +34,6 @@
     bool isInterface() const override;
     bool isEnum() const override;
     bool isTypeDef() const override;
-
-    std::string getJavaType() const override;
-
     bool needsEmbeddedReadWrite() const override;
     bool resultNeedsDeref() const override;
 
diff --git a/VectorType.cpp b/VectorType.cpp
index 555d28d..00e171c 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -53,8 +53,12 @@
     }
 }
 
-std::string VectorType::getJavaType() const {
-    return mElementType->getJavaType() + "[]";
+std::string VectorType::getJavaType(
+        std::string *extra, bool /* forInitializer */) const {
+    *extra = "[]";
+
+    std::string elementExtra;
+    return mElementType->getJavaType(&elementExtra) + elementExtra;
 }
 
 void VectorType::emitReaderWriter(
@@ -207,13 +211,15 @@
         const std::string &argName,
         bool isReader) const {
     if (mElementType->isCompoundType()) {
+        std::string extra;  // unused, because CompoundType leaves this empty.
+
         if (isReader) {
-            out << mElementType->getJavaType()
+            out << mElementType->getJavaType(&extra)
                 << ".readVectorFromParcel("
                 << parcelObj
                 << ");\n";
         } else {
-            out << mElementType->getJavaType()
+            out << mElementType->getJavaType(&extra)
                 << ".writeVectorToParcel("
                 << parcelObj
                 << ", "
@@ -248,17 +254,19 @@
 
 void VectorType::emitJavaFieldReaderWriter(
         Formatter &out,
+        size_t depth,
         const std::string &blobName,
         const std::string &fieldName,
         const std::string &offset,
         bool isReader) const {
     VectorType::EmitJavaFieldReaderWriterForElementType(
-            out, mElementType, blobName, fieldName, offset, isReader);
+            out, depth, mElementType, blobName, fieldName, offset, isReader);
 }
 
 // static
 void VectorType::EmitJavaFieldReaderWriterForElementType(
         Formatter &out,
+        size_t depth,
         const Type *elementType,
         const std::string &blobName,
         const std::string &fieldName,
@@ -287,8 +295,16 @@
             << offset
             << " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
 
-        out << "for (int _hidl_index = 0; _hidl_index < _hidl_vec_size; "
-            << "++_hidl_index) {\n";
+        std::string iteratorName = "_hidl_index_" + std::to_string(depth);
+
+        out << "for (int "
+            << iteratorName
+            << " = 0; "
+            << iteratorName
+            << " < _hidl_vec_size; "
+            << "++"
+            << iteratorName
+            << ") {\n";
 
         out.indent();
 
@@ -299,9 +315,10 @@
 
         elementType->emitJavaFieldReaderWriter(
                 out,
+                depth + 1,
                 "childBlob",
                 "_hidl_vec_element",
-                "_hidl_index * " + std::to_string(elementSize),
+                iteratorName + " * " + std::to_string(elementSize),
                 true /* isReader */);
 
         out << fieldName
@@ -342,16 +359,25 @@
         << elementSize
         << "));\n";
 
-    out << "for (int _hidl_index = 0; _hidl_index < _hidl_vec_size; "
-        << "++_hidl_index) {\n";
+    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
+
+    out << "for (int "
+        << iteratorName
+        << " = 0; "
+        << iteratorName
+        << " < _hidl_vec_size; "
+        << "++"
+        << iteratorName
+        << ") {\n";
 
     out.indent();
 
     elementType->emitJavaFieldReaderWriter(
             out,
+            depth + 1,
             "childBlob",
-            fieldName + ".elementAt(_hidl_index)",
-            "_hidl_index * " + std::to_string(elementSize),
+            fieldName + ".elementAt(" + iteratorName + ")",
+            iteratorName + " * " + std::to_string(elementSize),
             false /* isReader */);
 
     out.unindent();
diff --git a/VectorType.h b/VectorType.h
index 6655530..2c4c730 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -27,11 +27,13 @@
 
     void addNamedTypesToSet(std::set<const FQName> &set) const override;
 
-    std::string getCppType(StorageMode mode,
-                           std::string *extra,
-                           bool specifyNamespaces) const override;
+    std::string getCppType(
+            StorageMode mode,
+            std::string *extra,
+            bool specifyNamespaces) const override;
 
-    std::string getJavaType() const override;
+    std::string getJavaType(
+            std::string *extra, bool forInitializer) const override;
 
     void emitReaderWriter(
             Formatter &out,
@@ -64,6 +66,7 @@
 
     void emitJavaFieldReaderWriter(
             Formatter &out,
+            size_t depth,
             const std::string &blobName,
             const std::string &fieldName,
             const std::string &offset,
@@ -71,6 +74,7 @@
 
     static void EmitJavaFieldReaderWriterForElementType(
             Formatter &out,
+            size_t depth,
             const Type *elementType,
             const std::string &blobName,
             const std::string &fieldName,
diff --git a/generateJava.cpp b/generateJava.cpp
index e89a577..df239a2 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -33,7 +33,9 @@
         const TypedVar *arg,
         bool isReader) const {
     if (isReader) {
-        out << arg->type().getJavaType()
+        std::string extra;
+        out << arg->type().getJavaType(&extra)
+            << extra
             << " "
             << arg->name()
             << " = ";
@@ -270,7 +272,9 @@
         }
 
         if (returnsValue && !needsCallback) {
-            out << method->results()[0]->type().getJavaType();
+            std::string extra;
+            out << method->results()[0]->type().getJavaType(&extra)
+                << extra;
         } else {
             out << "void";
         }
@@ -330,7 +334,9 @@
 
             out << "public ";
             if (returnsValue && !needsCallback) {
-                out << method->results()[0]->type().getJavaType();
+                std::string extra;
+                out << method->results()[0]->type().getJavaType(&extra)
+                    << extra;
             } else {
                 out << "void";
             }
@@ -491,8 +497,10 @@
 
             if (!needsCallback && returnsValue) {
                 const TypedVar *returnArg = method->results()[0];
+                std::string extra;
 
-                out << returnArg->type().getJavaType()
+                out << returnArg->type().getJavaType(&extra)
+                    << extra
                     << " "
                     << returnArg->name()
                     << " = ";
diff --git a/test/java_test/hidl_test_java_native.cpp b/test/java_test/hidl_test_java_native.cpp
index 6e7cad1..fa79be7 100644
--- a/test/java_test/hidl_test_java_native.cpp
+++ b/test/java_test/hidl_test_java_native.cpp
@@ -47,6 +47,10 @@
             const hidl_vec<IBaz::Foo> &fooInput,
             someMethodWithFooVectors_cb _hidl_cb) override;
 
+    Return<void> transpose(
+            const IBase::StringMatrix5x3 &in,
+            transpose_cb _hidl_cb) override;
+
     Return<bool> someBoolMethod(bool x) override;
 
     Return<void> someBoolArrayMethod(
@@ -99,6 +103,8 @@
 static std::string to_string(const IBaz::Foo &foo);
 static std::string to_string(const hidl_string &s);
 static std::string to_string(bool x);
+static std::string to_string(const IBase::StringMatrix5x3 &M);
+static std::string to_string(const IBase::StringMatrix3x5 &M);
 
 template<class T>
 static std::string array_to_string(const T *array, size_t size) {
@@ -149,6 +155,34 @@
     return out;
 }
 
+static std::string to_string(const IBase::StringMatrix5x3 &M) {
+    std::string out;
+    out += "[";
+    for (int i = 0; i < 5; ++i) {
+        if (i > 0) {
+            out += ", ";
+        }
+        out += array_to_string(M.s[i], 3);
+    }
+    out += "]";
+
+    return out;
+}
+
+static std::string to_string(const IBase::StringMatrix3x5 &M) {
+    std::string out;
+    out += "[";
+    for (int i = 0; i < 3; ++i) {
+        if (i > 0) {
+            out += ", ";
+        }
+        out += array_to_string(M.s[i], 5);
+    }
+    out += "]";
+
+    return out;
+}
+
 Return<void> Baz::someOtherBaseMethod(
         const IBaz::Foo &foo, someOtherBaseMethod_cb _hidl_cb) {
     LOG(INFO) << "Baz::someOtherBaseMethod "
@@ -189,6 +223,22 @@
     return Void();
 }
 
+Return<void> Baz::transpose(
+        const IBase::StringMatrix5x3 &in, transpose_cb _hidl_cb) {
+    LOG(INFO) << "Baz::transpose " << to_string(in);
+
+    IBase::StringMatrix3x5 out;
+    for (size_t i = 0; i < 3; ++i) {
+        for (size_t j = 0; j < 5; ++j) {
+            out.s[i][j] = in.s[j][i];
+        }
+    }
+
+    _hidl_cb(out);
+
+    return Void();
+}
+
 Return<bool> Baz::someBoolMethod(bool x) {
     LOG(INFO) << "Baz::someBoolMethod(" << to_string(x) << ")";
 
@@ -515,6 +565,72 @@
                 }));
 }
 
+static std::string numberToEnglish(int x) {
+    static const char *const kDigits[] = {
+        "zero",
+        "one",
+        "two",
+        "three",
+        "four",
+        "five",
+        "six",
+        "seven",
+        "eight",
+        "nine",
+    };
+
+    if (x < 0) {
+        return "negative " + numberToEnglish(-x);
+    }
+
+    if (x < 10) {
+        return kDigits[x];
+    }
+
+    if (x <= 15) {
+        static const char *const kSpecialTens[] = {
+            "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
+        };
+
+        return kSpecialTens[x - 10];
+    }
+
+    if (x < 20) {
+        return std::string(kDigits[x % 10]) + "teen";
+    }
+
+    if (x < 100) {
+        static const char *const kDecades[] = {
+            "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
+            "eighty", "ninety",
+        };
+
+        return std::string(kDecades[x / 10 - 2]) + kDigits[x % 10];
+    }
+
+    return "positively huge!";
+}
+
+TEST_F(HidlTest, BazTransposeTest) {
+    IBase::StringMatrix5x3 in;
+
+    for (int i = 0; i < 5; ++i) {
+        for (int j = 0; j < 3; ++j) {
+            in.s[i][j] = numberToEnglish(3 * i + j + 1).c_str();
+        }
+    }
+
+    EXPECT_OK(baz->transpose(
+                in,
+                [&](const auto &out) {
+                    EXPECT_EQ(
+                        to_string(out),
+                        "[['one', 'four', 'seven', 'ten', 'thirteen'], "
+                         "['two', 'five', 'eight', 'eleven', 'fourteen'], "
+                         "['three', 'six', 'nine', 'twelve', 'fifteen']]");
+                }));
+}
+
 TEST_F(HidlTest, BazSomeBoolMethodTest) {
     auto result = baz->someBoolMethod(true);
     EXPECT_OK(result);
diff --git a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
index 01db507..b8932a7 100644
--- a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
+++ b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
@@ -179,6 +179,36 @@
         return "'" + s + "'";
     }
 
+    public static String toString(IBase.StringMatrix5x3 M) {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("[");
+        for (int i = 0; i < 5; ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(M.s[i]));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    public static String toString(IBase.StringMatrix3x5 M) {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("[");
+        for (int i = 0; i < 3; ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(M.s[i]));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
     private void ExpectTrue(boolean x) {
         if (x) {
             return;
@@ -214,6 +244,52 @@
         }
     }
 
+    private String numberToEnglish(int x) {
+        final String[] kDigits = {
+            "zero",
+            "one",
+            "two",
+            "three",
+            "four",
+            "five",
+            "six",
+            "seven",
+            "eight",
+            "nine",
+        };
+
+        if (x < 0) {
+            return "negative " + numberToEnglish(-x);
+        }
+
+        if (x < 10) {
+            return kDigits[x];
+        }
+
+        if (x <= 15) {
+            final String[] kSpecialTens = {
+                "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
+            };
+
+            return kSpecialTens[x - 10];
+        }
+
+        if (x < 20) {
+            return kDigits[x % 10] + "teen";
+        }
+
+        if (x < 100) {
+            final String[] kDecades = {
+                "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
+                "eighty", "ninety",
+            };
+
+            return kDecades[x / 10 - 2] + kDigits[x % 10];
+        }
+
+        return "positively huge!";
+    }
+
     private void client() {
         {
             // Test access through base interface binder.
@@ -351,6 +427,24 @@
                                 "Bar(z = 1.04, s = 'Hello, world 4')])]");
         }
 
+        {
+            IBase.StringMatrix5x3 in = new IBase.StringMatrix5x3();
+            for (int i = 0; i < 5; ++i) {
+                for (int j = 0; j < 3; ++j) {
+                    in.s[i][j] = numberToEnglish(3 * i + j + 1);
+                }
+            }
+
+            IBase.StringMatrix3x5 out = proxy.transpose(in);
+
+            // [[1 2 3] [4 5 6] [7 8 9] [10 11 12] [13 14 15]]^T
+            // = [[1 4 7 10 13] [2 5 8 11 14] [3 6 9 12 15]]
+            Expect(toString(out),
+                   "[['one', 'four', 'seven', 'ten', 'thirteen'], "
+                   +"['two', 'five', 'eight', 'eleven', 'fourteen'], "
+                   +"['three', 'six', 'nine', 'twelve', 'fifteen']]");
+        }
+
         Expect(toString(proxy.someBoolMethod(true)), "false");
 
         {
@@ -449,6 +543,19 @@
             return fooOutput;
         }
 
+        public IBase.StringMatrix3x5 transpose(IBase.StringMatrix5x3 in) {
+            Log.d(TAG, "Baz transpose " + HidlTestJava.toString(in));
+
+            IBase.StringMatrix3x5 out = new IBase.StringMatrix3x5();
+            for (int i = 0; i < 3; ++i) {
+                for (int j = 0; j < 5; ++j) {
+                    out.s[i][j] = in.s[j][i];
+                }
+            }
+
+            return out;
+        }
+
         public boolean someBoolMethod(boolean x) {
             Log.d(TAG, "Baz someBoolMethod(" + x + ")");