Skip to content

Commit f6b2319

Browse files
authored
gazelle: Populate plugins attributes with annotation processors (#276)
1 parent 01812dd commit f6b2319

File tree

21 files changed

+644
-98
lines changed

21 files changed

+644
-98
lines changed

java/gazelle/configure.go

+17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/bazel-contrib/rules_jvm/java/gazelle/javaconfig"
99
"github.com/bazel-contrib/rules_jvm/java/gazelle/private/javaparser"
1010
"github.com/bazel-contrib/rules_jvm/java/gazelle/private/maven"
11+
"github.com/bazel-contrib/rules_jvm/java/gazelle/private/types"
1112
"github.com/bazelbuild/bazel-gazelle/config"
1213
"github.com/bazelbuild/bazel-gazelle/rule"
1314
bzl "github.com/bazelbuild/buildtools/build"
@@ -64,6 +65,7 @@ func (jc *Configurer) KnownDirectives() []string {
6465
javaconfig.JavaTestMode,
6566
javaconfig.JavaGenerateProto,
6667
javaconfig.JavaMavenRepositoryName,
68+
javaconfig.JavaAnnotationProcessorPlugin,
6769
}
6870
}
6971

@@ -129,6 +131,21 @@ func (jc *Configurer) Configure(c *config.Config, rel string, f *rule.File) {
129131
jc.lang.logger.Fatal().Msgf("invalid value for directive %q: %s: possible values are true/false",
130132
javaconfig.JavaGenerateProto, d.Value)
131133
}
134+
case javaconfig.JavaAnnotationProcessorPlugin:
135+
// Format: # gazelle:java_annotation_processor_plugin com.example.AnnotationName com.example.AnnotationProcessorImpl
136+
parts := strings.Split(d.Value, " ")
137+
if len(parts) != 2 {
138+
jc.lang.logger.Fatal().Msgf("invalid value for directive %q: %s: expected an annotation class-name followed by a processor class-name", javaconfig.JavaAnnotationProcessorPlugin, d.Value)
139+
}
140+
annotationClassName, err := types.ParseClassName(parts[0])
141+
if err != nil {
142+
jc.lang.logger.Fatal().Msgf("invalid value for directive %q: %q: couldn't parse annotation processor annotation class-name: %v", javaconfig.JavaAnnotationProcessorPlugin, parts[0], err)
143+
}
144+
processorClassName, err := types.ParseClassName(parts[1])
145+
if err != nil {
146+
jc.lang.logger.Fatal().Msgf("invalid value for directive %q: %q: couldn't parse annotation processor class-name: %v", javaconfig.JavaAnnotationProcessorPlugin, parts[1], err)
147+
}
148+
cfg.AddAnnotationProcessorPlugin(*annotationClassName, *processorClassName)
132149
}
133150
}
134151
}

java/gazelle/generate.go

+22-10
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
127127
// All java packages present in this bazel package.
128128
allPackageNames := sorted_set.NewSortedSetFn([]types.PackageName{}, types.PackageNameLess)
129129

130+
annotationProcessorClasses := sorted_set.NewSortedSetFn(nil, types.ClassNameLess)
131+
130132
if isModule {
131133
for mRel, mJavaPkg := range l.javaPackageCache {
132134
if !strings.HasPrefix(mRel, args.Rel) {
@@ -152,6 +154,9 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
152154
accumulateJavaFile(cfg, testJavaFiles, testHelperJavaFiles, separateTestJavaFiles, file, mJavaPkg.PerClassMetadata, log)
153155
}
154156
}
157+
for _, annotationClass := range mJavaPkg.AllAnnotations().SortedSlice() {
158+
annotationProcessorClasses.AddAll(cfg.GetAnnotationProcessorPluginClasses(annotationClass))
159+
}
155160
}
156161
} else {
157162
allPackageNames.Add(javaPkg.Name)
@@ -174,6 +179,9 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
174179
productionJavaFiles.Add(path)
175180
}
176181
}
182+
for _, annotationClass := range javaPkg.AllAnnotations().SortedSlice() {
183+
annotationProcessorClasses.AddAll(cfg.GetAnnotationProcessorPluginClasses(annotationClass))
184+
}
177185
}
178186

179187
allPackageNamesSlice := allPackageNames.SortedSlice()
@@ -192,7 +200,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
192200
}
193201

194202
if productionJavaFiles.Len() > 0 {
195-
l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), productionJavaFiles.SortedSlice(), allPackageNames, nonLocalProductionJavaImports, nonLocalJavaExports, false, javaLibraryKind, &res)
203+
l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), productionJavaFiles.SortedSlice(), allPackageNames, nonLocalProductionJavaImports, nonLocalJavaExports, annotationProcessorClasses, false, javaLibraryKind, &res)
196204
}
197205

198206
var testHelperJavaClasses *sorted_set.SortedSet[types.ClassName]
@@ -228,7 +236,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
228236
testJavaImportsWithHelpers.Add(tf.pkg)
229237
srcs = append(srcs, tf.pathRelativeToBazelWorkspaceRoot)
230238
}
231-
l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), srcs, packages, testJavaImports, nonLocalJavaExports, true, javaLibraryKind, &res)
239+
l.generateJavaLibrary(args.File, args.Rel, filepath.Base(args.Rel), srcs, packages, testJavaImports, nonLocalJavaExports, annotationProcessorClasses, true, javaLibraryKind, &res)
232240
}
233241
}
234242

@@ -240,7 +248,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
240248
case "file":
241249
for _, tf := range testJavaFiles.SortedSlice() {
242250
separateJavaTestReasons := separateTestJavaFiles[tf]
243-
l.generateJavaTest(args.File, args.Rel, cfg.MavenRepositoryName(), tf, isModule, testJavaImportsWithHelpers, nil, separateJavaTestReasons.wrapper, separateJavaTestReasons.attributes, &res)
251+
l.generateJavaTest(args.File, args.Rel, cfg.MavenRepositoryName(), tf, isModule, testJavaImportsWithHelpers, annotationProcessorClasses, nil, separateJavaTestReasons.wrapper, separateJavaTestReasons.attributes, &res)
244252
}
245253

246254
case "suite":
@@ -268,6 +276,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
268276
packageNames,
269277
cfg.MavenRepositoryName(),
270278
testJavaImportsWithHelpers,
279+
annotationProcessorClasses,
271280
cfg.GetCustomJavaTestFileSuffixes(),
272281
testHelperJavaFiles.Len() > 0,
273282
&res,
@@ -284,7 +293,7 @@ func (l javaLang) GenerateRules(args language.GenerateArgs) language.GenerateRes
284293
testHelperDep = ptr(testHelperLibname(suiteName))
285294
}
286295
separateJavaTestReasons := separateTestJavaFiles[src]
287-
l.generateJavaTest(args.File, args.Rel, cfg.MavenRepositoryName(), src, isModule, testJavaImportsWithHelpers, testHelperDep, separateJavaTestReasons.wrapper, separateJavaTestReasons.attributes, &res)
296+
l.generateJavaTest(args.File, args.Rel, cfg.MavenRepositoryName(), src, isModule, testJavaImportsWithHelpers, annotationProcessorClasses, testHelperDep, separateJavaTestReasons.wrapper, separateJavaTestReasons.attributes, &res)
288297
}
289298
}
290299
}
@@ -415,7 +424,7 @@ func addFilteringOutOwnPackage(to *sorted_set.SortedSet[types.PackageName], from
415424

416425
func accumulateJavaFile(cfg *javaconfig.Config, testJavaFiles, testHelperJavaFiles *sorted_set.SortedSet[javaFile], separateTestJavaFiles map[javaFile]separateJavaTestReasons, file javaFile, perClassMetadata map[string]java.PerClassMetadata, log zerolog.Logger) {
417426
if cfg.IsJavaTestFile(filepath.Base(file.pathRelativeToBazelWorkspaceRoot)) {
418-
annotationClassNames := sorted_set.NewSortedSet[string](nil)
427+
annotationClassNames := sorted_set.NewSortedSetFn[types.ClassName](nil, types.ClassNameLess)
419428
metadataForClass := perClassMetadata[file.ClassName().FullyQualifiedClassName()]
420429
annotationClassNames.AddAll(metadataForClass.AnnotationClassNames)
421430
for _, key := range metadataForClass.MethodAnnotationClassNames.Keys() {
@@ -425,15 +434,15 @@ func accumulateJavaFile(cfg *javaconfig.Config, testJavaFiles, testHelperJavaFil
425434
perFileAttrs := make(map[string]bzl.Expr)
426435
wrapper := ""
427436
for _, annotationClassName := range annotationClassNames.SortedSlice() {
428-
if attrs, ok := cfg.AttributesForAnnotation(annotationClassName); ok {
437+
if attrs, ok := cfg.AttributesForAnnotation(annotationClassName.FullyQualifiedClassName()); ok {
429438
for k, v := range attrs {
430439
if old, ok := perFileAttrs[k]; ok {
431440
log.Error().Str("file", file.pathRelativeToBazelWorkspaceRoot).Msgf("Saw conflicting attr overrides from annotations for attribute %v: %v and %v. Picking one at random.", k, old, v)
432441
}
433442
perFileAttrs[k] = v
434443
}
435444
}
436-
newWrapper, ok := cfg.WrapperForAnnotation(annotationClassName)
445+
newWrapper, ok := cfg.WrapperForAnnotation(annotationClassName.FullyQualifiedClassName())
437446
if ok {
438447
if wrapper != "" {
439448
log.Error().Str("file", file.pathRelativeToBazelWorkspaceRoot).Msgf("Saw conflicting wrappers from annotations: %v and %v. Picking one at random.", wrapper, newWrapper)
@@ -453,7 +462,7 @@ func accumulateJavaFile(cfg *javaconfig.Config, testJavaFiles, testHelperJavaFil
453462
}
454463
}
455464

456-
func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBazelWorkspace string, name string, srcsRelativeToBazelWorkspace []string, packages, imports *sorted_set.SortedSet[types.PackageName], exports *sorted_set.SortedSet[types.PackageName], testonly bool, javaLibraryRuleKind string, res *language.GenerateResult) {
465+
func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBazelWorkspace string, name string, srcsRelativeToBazelWorkspace []string, packages, imports *sorted_set.SortedSet[types.PackageName], exports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], testonly bool, javaLibraryRuleKind string, res *language.GenerateResult) {
457466
const ruleKind = "java_library"
458467
r := rule.NewRule(ruleKind, name)
459468

@@ -487,6 +496,7 @@ func (l javaLang) generateJavaLibrary(file *rule.File, pathToPackageRelativeToBa
487496
PackageNames: packages,
488497
ImportedPackageNames: imports,
489498
ExportedPackageNames: exports,
499+
AnnotationProcessors: annotationProcessorClasses,
490500
}
491501
res.Imports = append(res.Imports, resolveInput)
492502
}
@@ -511,7 +521,7 @@ func (l javaLang) generateJavaBinary(file *rule.File, m types.ClassName, libName
511521
})
512522
}
513523

514-
func (l javaLang) generateJavaTest(file *rule.File, pathToPackageRelativeToBazelWorkspace string, mavenRepositoryName string, f javaFile, includePackageInName bool, imports *sorted_set.SortedSet[types.PackageName], depOnTestHelpers *string, wrapper string, extraAttributes map[string]bzl.Expr, res *language.GenerateResult) {
524+
func (l javaLang) generateJavaTest(file *rule.File, pathToPackageRelativeToBazelWorkspace string, mavenRepositoryName string, f javaFile, includePackageInName bool, imports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], depOnTestHelpers *string, wrapper string, extraAttributes map[string]bzl.Expr, res *language.GenerateResult) {
515525
className := f.ClassName()
516526
fullyQualifiedTestClass := className.FullyQualifiedClassName()
517527
var testName string
@@ -571,6 +581,7 @@ func (l javaLang) generateJavaTest(file *rule.File, pathToPackageRelativeToBazel
571581
resolveInput := types.ResolveInput{
572582
PackageNames: sorted_set.NewSortedSetFn([]types.PackageName{f.pkg}, types.PackageNameLess),
573583
ImportedPackageNames: testImports,
584+
AnnotationProcessors: annotationProcessorClasses,
574585
}
575586
res.Imports = append(res.Imports, resolveInput)
576587
}
@@ -598,7 +609,7 @@ var junit5RuntimeDeps = []string{
598609
"org.junit.platform:junit-platform-reporting",
599610
}
600611

601-
func (l javaLang) generateJavaTestSuite(file *rule.File, name string, srcs []string, packageNames *sorted_set.SortedSet[types.PackageName], mavenRepositoryName string, imports *sorted_set.SortedSet[types.PackageName], customTestSuffixes *[]string, hasHelpers bool, res *language.GenerateResult) {
612+
func (l javaLang) generateJavaTestSuite(file *rule.File, name string, srcs []string, packageNames *sorted_set.SortedSet[types.PackageName], mavenRepositoryName string, imports *sorted_set.SortedSet[types.PackageName], annotationProcessorClasses *sorted_set.SortedSet[types.ClassName], customTestSuffixes *[]string, hasHelpers bool, res *language.GenerateResult) {
602613
const ruleKind = "java_test_suite"
603614
r := rule.NewRule(ruleKind, name)
604615
r.SetAttr("srcs", srcs)
@@ -636,6 +647,7 @@ func (l javaLang) generateJavaTestSuite(file *rule.File, name string, srcs []str
636647
resolveInput := types.ResolveInput{
637648
PackageNames: packageNames,
638649
ImportedPackageNames: suiteImports,
650+
AnnotationProcessors: annotationProcessorClasses,
639651
}
640652
res.Imports = append(res.Imports, resolveInput)
641653
}

java/gazelle/generate_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func TestSingleJavaTestFile(t *testing.T) {
159159
var res language.GenerateResult
160160

161161
l := newTestJavaLang(t)
162-
l.generateJavaTest(nil, "", "maven", f, tc.includePackageInName, stringsToPackageNames(tc.importedPackages), nil, tc.wrapper, nil, &res)
162+
l.generateJavaTest(nil, "", "maven", f, tc.includePackageInName, stringsToPackageNames(tc.importedPackages), nil, nil, tc.wrapper, nil, &res)
163163

164164
require.Len(t, res.Gen, 1, "want 1 generated rule")
165165

@@ -252,7 +252,7 @@ func TestSuite(t *testing.T) {
252252
var res language.GenerateResult
253253

254254
l := newTestJavaLang(t)
255-
l.generateJavaTestSuite(nil, "blah", []string{src}, stringsToPackageNames([]string{pkg}), "maven", stringsToPackageNames(tc.importedPackages), nil, false, &res)
255+
l.generateJavaTestSuite(nil, "blah", []string{src}, stringsToPackageNames([]string{pkg}), "maven", stringsToPackageNames(tc.importedPackages), nil, nil, false, &res)
256256

257257
require.Len(t, res.Gen, 1, "want 1 generated rule")
258258

java/gazelle/javaconfig/BUILD.bazel

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ go_library(
99
importpath = "github.com/bazel-contrib/rules_jvm/java/gazelle/javaconfig",
1010
visibility = ["//visibility:public"],
1111
deps = [
12+
"//java/gazelle/private/sorted_set",
13+
"//java/gazelle/private/types",
1214
"@com_github_bazelbuild_buildtools//build",
1315
],
1416
)

java/gazelle/javaconfig/config.go

+37-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"path/filepath"
77
"strings"
88

9+
"github.com/bazel-contrib/rules_jvm/java/gazelle/private/sorted_set"
10+
"github.com/bazel-contrib/rules_jvm/java/gazelle/private/types"
911
bzl "github.com/bazelbuild/buildtools/build"
1012
)
1113

@@ -47,6 +49,10 @@ const (
4749
// JavaMavenRepositoryName tells the code generator what the repository name that contains all maven dependencies is.
4850
// Defaults to "maven"
4951
JavaMavenRepositoryName = "java_maven_repository_name"
52+
53+
// JavaAnnotationProcessorPlugin tells the code generator about specific java_plugin targets needed to process
54+
// specific annotations.
55+
JavaAnnotationProcessorPlugin = "java_annotation_processor_plugin"
5056
)
5157

5258
// Configs is an extension of map[string]*Config. It provides finding methods
@@ -60,6 +66,10 @@ func (c *Config) NewChild() *Config {
6066
for key, value := range c.excludedArtifacts {
6167
clonedExcludedArtifacts[key] = value
6268
}
69+
annotationProcessorFullQualifiedClassToPluginClass := make(map[string]*sorted_set.SortedSet[types.ClassName])
70+
for key, value := range c.annotationProcessorFullQualifiedClassToPluginClass {
71+
annotationProcessorFullQualifiedClassToPluginClass[key] = value.Clone()
72+
}
6373
return &Config{
6474
parent: c,
6575
extensionEnabled: c.extensionEnabled,
@@ -74,6 +84,7 @@ func (c *Config) NewChild() *Config {
7484
annotationToWrapper: c.annotationToWrapper,
7585
excludedArtifacts: clonedExcludedArtifacts,
7686
mavenRepositoryName: c.mavenRepositoryName,
87+
annotationProcessorFullQualifiedClassToPluginClass: annotationProcessorFullQualifiedClassToPluginClass,
7788
}
7889
}
7990

@@ -91,18 +102,19 @@ func (c *Configs) ParentForPackage(pkg string) *Config {
91102
type Config struct {
92103
parent *Config
93104

94-
extensionEnabled bool
95-
isModuleRoot bool
96-
generateProto bool
97-
mavenInstallFile string
98-
moduleGranularity string
99-
repoRoot string
100-
testMode string
101-
customTestFileSuffixes *[]string
102-
excludedArtifacts map[string]struct{}
103-
annotationToAttribute map[string]map[string]bzl.Expr
104-
annotationToWrapper map[string]string
105-
mavenRepositoryName string
105+
extensionEnabled bool
106+
isModuleRoot bool
107+
generateProto bool
108+
mavenInstallFile string
109+
moduleGranularity string
110+
repoRoot string
111+
testMode string
112+
customTestFileSuffixes *[]string
113+
excludedArtifacts map[string]struct{}
114+
annotationToAttribute map[string]map[string]bzl.Expr
115+
annotationToWrapper map[string]string
116+
mavenRepositoryName string
117+
annotationProcessorFullQualifiedClassToPluginClass map[string]*sorted_set.SortedSet[types.ClassName]
106118
}
107119

108120
type LoadInfo struct {
@@ -125,6 +137,7 @@ func New(repoRoot string) *Config {
125137
annotationToAttribute: make(map[string]map[string]bzl.Expr),
126138
annotationToWrapper: make(map[string]string),
127139
mavenRepositoryName: "maven",
140+
annotationProcessorFullQualifiedClassToPluginClass: make(map[string]*sorted_set.SortedSet[types.ClassName]),
128141
}
129142
}
130143

@@ -269,6 +282,18 @@ func (c *Config) IsTestRule(ruleKind string) bool {
269282
return false
270283
}
271284

285+
func (c *Config) GetAnnotationProcessorPluginClasses(annotationClass types.ClassName) *sorted_set.SortedSet[types.ClassName] {
286+
return c.annotationProcessorFullQualifiedClassToPluginClass[annotationClass.FullyQualifiedClassName()]
287+
}
288+
289+
func (c *Config) AddAnnotationProcessorPlugin(annotationClass types.ClassName, processorClass types.ClassName) {
290+
fullyQualifiedAnnotationClass := annotationClass.FullyQualifiedClassName()
291+
if _, ok := c.annotationProcessorFullQualifiedClassToPluginClass[fullyQualifiedAnnotationClass]; !ok {
292+
c.annotationProcessorFullQualifiedClassToPluginClass[fullyQualifiedAnnotationClass] = sorted_set.NewSortedSetFn[types.ClassName](nil, types.ClassNameLess)
293+
}
294+
c.annotationProcessorFullQualifiedClassToPluginClass[fullyQualifiedAnnotationClass].Add(processorClass)
295+
}
296+
272297
func equalStringSlices(l, r []string) bool {
273298
if len(l) != len(r) {
274299
return false

java/gazelle/private/java/package.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,22 @@ type Package struct {
2121
PerClassMetadata map[string]PerClassMetadata
2222
}
2323

24+
func (p *Package) AllAnnotations() *sorted_set.SortedSet[types.ClassName] {
25+
annotations := sorted_set.NewSortedSetFn(nil, types.ClassNameLess)
26+
for _, pcm := range p.PerClassMetadata {
27+
annotations.AddAll(pcm.AnnotationClassNames)
28+
for _, method := range pcm.MethodAnnotationClassNames.Keys() {
29+
annotations.AddAll(pcm.MethodAnnotationClassNames.Values(method))
30+
}
31+
for _, field := range pcm.FieldAnnotationClassNames.Keys() {
32+
annotations.AddAll(pcm.FieldAnnotationClassNames.Values(field))
33+
}
34+
}
35+
return annotations
36+
}
37+
2438
type PerClassMetadata struct {
25-
AnnotationClassNames *sorted_set.SortedSet[string]
26-
MethodAnnotationClassNames *sorted_multiset.SortedMultiSet[string, string]
39+
AnnotationClassNames *sorted_set.SortedSet[types.ClassName]
40+
MethodAnnotationClassNames *sorted_multiset.SortedMultiSet[string, types.ClassName]
41+
FieldAnnotationClassNames *sorted_multiset.SortedMultiSet[string, types.ClassName]
2742
}

0 commit comments

Comments
 (0)