union supports @JavaDerive(toString=true)
When annotated with @JavaDerive(toString=true), the compiler generates
toString() for union. And the string representation for a union is look
like a constructor call.
@JavaDerive(toString=true)
union Foo {
int num;
String str;
}
Union.n(42).toString() == "Union.n(42)"
Bug: 171271915
Test: aidl_unittests / aidl_integration_test
Change-Id: Ie1a631070456cc53f3f9f8069c2b16916a8b4723
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 841e730..0fa2dd1 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -1150,7 +1150,7 @@
std::set<AidlAnnotation::Type> AidlUnionDecl::GetSupportedAnnotations() const {
return {AidlAnnotation::Type::VINTF_STABILITY, AidlAnnotation::Type::HIDE,
- AidlAnnotation::Type::JAVA_PASSTHROUGH};
+ AidlAnnotation::Type::JAVA_PASSTHROUGH, AidlAnnotation::Type::JAVA_DERIVE};
}
void AidlUnionDecl::Dump(CodeWriter* writer) const {
diff --git a/aidl_to_java.cpp b/aidl_to_java.cpp
index 9fa691a..ba00dee 100644
--- a/aidl_to_java.cpp
+++ b/aidl_to_java.cpp
@@ -768,8 +768,6 @@
void ToStringFor(const CodeGeneratorContext& c) {
if (c.type.IsArray()) {
- // Arrays can be null
- c.writer << c.var << " == null ? \"null\" : ";
c.writer << "java.util.Arrays.toString(" << c.var << ")";
return;
}
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index a734b77..7803521 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -580,24 +580,48 @@
EXPECT_EQ(expected_stderr, GetCapturedStderr());
}
-TEST_F(AidlTest, ParsesJavaDeriveAnnotation) {
- io_delegate_.SetFileContents("a/IFoo.aidl", R"(package a;
- @JavaDerive(toString=true) parcelable IFoo { int a; float b; })");
- Options java_options = Options::From("aidl --lang=java -o out a/IFoo.aidl");
+TEST_F(AidlTest, ParcelableSupportJavaDeriveToString) {
+ io_delegate_.SetFileContents("a/Foo.aidl", R"(package a;
+ @JavaDerive(toString=true) parcelable Foo { int a; float b; })");
+ Options java_options = Options::From("aidl --lang=java -o out a/Foo.aidl");
EXPECT_EQ(0, ::android::aidl::compile_aidl(java_options, io_delegate_));
string java_out;
- EXPECT_TRUE(io_delegate_.GetWrittenContents("out/a/IFoo.java", &java_out));
+ EXPECT_TRUE(io_delegate_.GetWrittenContents("out/a/Foo.java", &java_out));
EXPECT_THAT(java_out, testing::HasSubstr("public String toString() {"));
// Other backends shouldn't be bothered
- Options cpp_options = Options::From("aidl --lang=cpp -o out -h out a/IFoo.aidl");
+ Options cpp_options = Options::From("aidl --lang=cpp -o out -h out a/Foo.aidl");
EXPECT_EQ(0, ::android::aidl::compile_aidl(cpp_options, io_delegate_));
- Options ndk_options = Options::From("aidl --lang=ndk -o out -h out a/IFoo.aidl");
+ Options ndk_options = Options::From("aidl --lang=ndk -o out -h out a/Foo.aidl");
EXPECT_EQ(0, ::android::aidl::compile_aidl(ndk_options, io_delegate_));
}
+TEST_F(AidlTest, UnionSupportJavaDeriveToString) {
+ io_delegate_.SetFileContents("a/Foo.aidl", R"(package a;
+ @JavaDerive(toString=true) union Foo { int a; int[] b; })");
+ CaptureStderr();
+ Options java_options = Options::From("aidl --lang=java -o out a/Foo.aidl");
+ EXPECT_EQ(0, ::android::aidl::compile_aidl(java_options, io_delegate_));
+ EXPECT_EQ("", GetCapturedStderr());
+
+ const string expected_to_string_method = R"--(
+ @Override
+ public String toString() {
+ switch (_tag) {
+ case a: return "a.Foo.a(" + (getA()) + ")";
+ case b: return "a.Foo.b(" + (java.util.Arrays.toString(getB())) + ")";
+ }
+ throw new IllegalStateException("unknown field: " + _tag);
+ }
+)--";
+
+ string java_out;
+ EXPECT_TRUE(io_delegate_.GetWrittenContents("out/a/Foo.java", &java_out));
+ EXPECT_THAT(java_out, testing::HasSubstr(expected_to_string_method));
+}
+
TEST_F(AidlTest, RejectsJavaDeriveAnnotation) {
{
io_delegate_.SetFileContents("a/Foo.aidl",
diff --git a/generate_java.cpp b/generate_java.cpp
index 4d2d4f3..069a20d 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -231,6 +231,30 @@
out << "}\n";
}
+void GenerateToString(CodeWriter& out, const AidlUnionDecl& parcel,
+ const AidlTypenames& typenames) {
+ out << "@Override\n";
+ out << "public String toString() {\n";
+ out.Indent();
+ out << "switch (_tag) {\n";
+ for (const auto& field : parcel.GetFields()) {
+ CodeGeneratorContext ctx{
+ .writer = out,
+ .typenames = typenames,
+ .type = field->GetType(),
+ .var = getter_name(*field) + "()",
+ };
+ out << "case " << field->GetName() << ": return \"" << parcel.GetCanonicalName() << "."
+ << field->GetName() << "(\" + (";
+ ToStringFor(ctx);
+ out << ") + \")\";\n";
+ }
+ out << "}\n";
+ out << "throw new IllegalStateException(\"unknown field: \" + _tag);\n";
+ out.Dedent();
+ out << "}\n";
+}
+
template <typename ParcelableType>
void GenerateDerivedMethods(CodeWriter& out, const ParcelableType& parcel,
const AidlTypenames& typenames) {
@@ -798,6 +822,7 @@
GenerateParcelableDescribeContents(out, *decl, typenames);
out << "\n";
+ GenerateDerivedMethods(out, *decl, typenames);
// helper: _assertTag
out << "private void _assertTag(" + tag_type + " tag) {\n";