[pigeon] adds option for java output to have the Generated annotation (#2261)

* [pigeon] adds option for java output to have the Generated annotation

* added negative test
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index a2f2819..9a73a6c 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.1.7
+
+* [java] Adds option to add javax.annotation.Generated annotation.
+
 ## 3.1.6
 
 * Supports newer versions of `analyzer`.
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index 1d69e09..0da3112 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -9,7 +9,7 @@
 import 'ast.dart';
 
 /// The current version of pigeon. This must match the version in pubspec.yaml.
-const String pigeonVersion = '3.1.6';
+const String pigeonVersion = '3.1.7';
 
 /// Read all the content from [stdin] to a String.
 String readStdin() {
diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart
index 7e88c64..7b6d741 100644
--- a/packages/pigeon/lib/java_generator.dart
+++ b/packages/pigeon/lib/java_generator.dart
@@ -14,6 +14,7 @@
     this.className,
     this.package,
     this.copyrightHeader,
+    this.useGeneratedAnnotation,
   });
 
   /// The name of the class that will house all the generated classes.
@@ -25,6 +26,11 @@
   /// A copyright header that will get prepended to generated code.
   final Iterable<String>? copyrightHeader;
 
+  /// Determines if the `javax.annotation.Generated` is used in the output. This
+  /// is false by default since that dependency isn't available in plugins by
+  /// default .
+  final bool? useGeneratedAnnotation;
+
   /// Creates a [JavaOptions] from a Map representation where:
   /// `x = JavaOptions.fromMap(x.toMap())`.
   static JavaOptions fromMap(Map<String, Object> map) {
@@ -34,6 +40,7 @@
       className: map['className'] as String?,
       package: map['package'] as String?,
       copyrightHeader: copyrightHeader?.cast<String>(),
+      useGeneratedAnnotation: map['useGeneratedAnnotation'] as bool?,
     );
   }
 
@@ -44,6 +51,8 @@
       if (className != null) 'className': className!,
       if (package != null) 'package': package!,
       if (copyrightHeader != null) 'copyrightHeader': copyrightHeader!,
+      if (useGeneratedAnnotation != null)
+        'useGeneratedAnnotation': useGeneratedAnnotation!,
     };
     return result;
   }
@@ -669,6 +678,9 @@
   indent.writeln('/** Generated class from Pigeon. */');
   indent.writeln(
       '@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})');
+  if (options.useGeneratedAnnotation ?? false) {
+    indent.writeln('@javax.annotation.Generated("dev.flutter.pigeon")');
+  }
   indent.write('public class ${options.className!} ');
   indent.scoped('{', '}', () {
     for (final Enum anEnum in root.enums) {
diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart
index 2a77a19..f784c1b 100644
--- a/packages/pigeon/lib/pigeon_lib.dart
+++ b/packages/pigeon/lib/pigeon_lib.dart
@@ -1135,6 +1135,8 @@
     ..addOption('java_out', help: 'Path to generated Java file (.java).')
     ..addOption('java_package',
         help: 'The package that generated Java code will be in.')
+    ..addFlag('java_use_generated_annotation',
+        help: 'Adds the java.annotation.Generated annotation to the output.')
     ..addOption('experimental_cpp_header_out',
         help: 'Path to generated C++ header file (.h). (experimental)')
     ..addOption('experimental_cpp_source_out',
@@ -1178,6 +1180,7 @@
       javaOut: results['java_out'],
       javaOptions: JavaOptions(
         package: results['java_package'],
+        useGeneratedAnnotation: results['java_use_generated_annotation'],
       ),
       cppHeaderOut: results['experimental_cpp_header_out'],
       cppSourceOut: results['experimental_cpp_source_out'],
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index c148c0f..cb09a19 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
 repository: https://github.com/flutter/packages/tree/main/packages/pigeon
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon
-version: 3.1.6 # This must match the version in lib/generator_tools.dart
+version: 3.1.7 # This must match the version in lib/generator_tools.dart
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart
index fd8df7b..ba076fd 100644
--- a/packages/pigeon/test/java_generator_test.dart
+++ b/packages/pigeon/test/java_generator_test.dart
@@ -1048,4 +1048,40 @@
         contains(
             'new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.Api.doit", getCodec(), taskQueue)'));
   });
+
+  test('generated annotation', () {
+    final Class klass = Class(
+      name: 'Foobar',
+      fields: <NamedType>[],
+    );
+    final Root root = Root(
+      apis: <Api>[],
+      classes: <Class>[klass],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const JavaOptions javaOptions =
+        JavaOptions(className: 'Messages', useGeneratedAnnotation: true);
+    generateJava(javaOptions, root, sink);
+    final String code = sink.toString();
+    expect(code, contains('@javax.annotation.Generated("dev.flutter.pigeon")'));
+  });
+
+  test('no generated annotation', () {
+    final Class klass = Class(
+      name: 'Foobar',
+      fields: <NamedType>[],
+    );
+    final Root root = Root(
+      apis: <Api>[],
+      classes: <Class>[klass],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const JavaOptions javaOptions = JavaOptions(className: 'Messages');
+    generateJava(javaOptions, root, sink);
+    final String code = sink.toString();
+    expect(code,
+        isNot(contains('@javax.annotation.Generated("dev.flutter.pigeon")')));
+  });
 }
diff --git a/packages/pigeon/test/pigeon_lib_test.dart b/packages/pigeon/test/pigeon_lib_test.dart
index 242a145..12bf9dc 100644
--- a/packages/pigeon/test/pigeon_lib_test.dart
+++ b/packages/pigeon/test/pigeon_lib_test.dart
@@ -98,6 +98,12 @@
     expect(opts.cppHeaderOut, equals('foo.h'));
   });
 
+  test('parse args - java_use_generated_annotation', () {
+    final PigeonOptions opts =
+        Pigeon.parseArgs(<String>['--java_use_generated_annotation']);
+    expect(opts.javaOptions!.useGeneratedAnnotation, isTrue);
+  });
+
   test('parse args - experimental_cpp_source_out', () {
     final PigeonOptions opts =
         Pigeon.parseArgs(<String>['--experimental_cpp_source_out', 'foo.cpp']);