From 8e40763559f4d32d51a65f5f53d8334299420969 Mon Sep 17 00:00:00 2001 From: gjoranv Date: Fri, 19 May 2023 17:21:04 +0200 Subject: Process @PublicApi annotation and collect annotated packages. --- .../plugin/classanalysis/AnalyzeClassVisitor.java | 8 +++- .../plugin/classanalysis/ClassFileMetaData.java | 16 ++++++-- .../plugin/classanalysis/PackageInfo.java | 22 +++++++++++ .../plugin/classanalysis/PackageTally.java | 44 +++++++++++----------- .../plugin/classanalysis/AnalyzeClassTest.java | 18 +++++---- .../classanalysis/sampleclasses/package-info.java | 2 + 6 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java (limited to 'bundle-plugin/src') diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java index 46a35b07ea7..e57af606b3a 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassVisitor.java @@ -1,6 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.plugin.classanalysis; +import com.yahoo.api.annotations.PublicApi; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; import org.apache.maven.artifact.versioning.ArtifactVersion; @@ -28,6 +29,7 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { private String name = null; private final Set imports = new HashSet<>(); private Optional exportPackageAnnotation = Optional.empty(); + private boolean isPublicApi = false; private final Optional defaultExportPackageVersion; @@ -159,6 +161,9 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (ExportPackage.class.getName().equals(Type.getType(desc).getClassName())) { return visitExportPackage(); + } if (PublicApi.class.getName().equals(Type.getType(desc).getClassName())) { + isPublicApi = true; + return null; } else { if (visible) { addImportWithTypeDesc(desc); @@ -169,7 +174,8 @@ class AnalyzeClassVisitor extends ClassVisitor implements ImportCollector { ClassFileMetaData result() { assert (!imports.contains("int")); - return new ClassFileMetaData(name, imports, exportPackageAnnotation); + var packageInfo = new PackageInfo(Packages.packageName(name), exportPackageAnnotation, isPublicApi); + return new ClassFileMetaData(name, imports, packageInfo); } } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java index 5601430a27f..7e2f59c1e4d 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/ClassFileMetaData.java @@ -14,12 +14,12 @@ public class ClassFileMetaData { private final String name; private final Set referencedClasses; - private final Optional exportPackage; + private final PackageInfo packageInfo; - public ClassFileMetaData(String name, Set referencedClasses, Optional exportPackage) { + public ClassFileMetaData(String name, Set referencedClasses, PackageInfo packageInfo) { this.name = name; this.referencedClasses = referencedClasses; - this.exportPackage = exportPackage; + this.packageInfo = packageInfo; } public String getName() { @@ -30,8 +30,16 @@ public class ClassFileMetaData { return referencedClasses; } + public PackageInfo packageInfo() { + return packageInfo; + } + public Optional getExportPackage() { - return exportPackage; + return packageInfo.exportPackage(); + } + + public boolean isPublicApi() { + return packageInfo.isPublicApi(); } } diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java new file mode 100644 index 00000000000..491f6d2a743 --- /dev/null +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageInfo.java @@ -0,0 +1,22 @@ +package com.yahoo.container.plugin.classanalysis; + +import java.util.Optional; + +/** + * The package + * + * @author gjoranv + */ +record PackageInfo(String name, Optional exportPackage, boolean isPublicApi) { + + PackageInfo { + if (exportPackage.isEmpty() && isPublicApi) { + throw new IllegalArgumentException("Package %s is declared PublicApi, but is not exported.".formatted(name)); + } + } + + PackageInfo hasExportPackageOrElse(PackageInfo other) { + return exportPackage().isPresent() ? this : other; + } + +} diff --git a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java index 03398307e03..6e8fc89c605 100644 --- a/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java +++ b/bundle-plugin/src/main/java/com/yahoo/container/plugin/classanalysis/PackageTally.java @@ -17,16 +17,17 @@ import java.util.stream.Collectors; * @author ollivir */ public class PackageTally { - private final Map> definedPackagesMap; + + private final Map definedPackages; private final Set referencedPackagesUnfiltered; - PackageTally(Map> definedPackagesMap, Set referencedPackagesUnfiltered) { - this.definedPackagesMap = definedPackagesMap; + PackageTally(Map definedPackages, Set referencedPackagesUnfiltered) { + this.definedPackages = definedPackages; this.referencedPackagesUnfiltered = referencedPackagesUnfiltered; } public Set definedPackages() { - return definedPackagesMap.keySet(); + return definedPackages.keySet(); } public Set referencedPackages() { @@ -35,8 +36,8 @@ public class PackageTally { public Map exportedPackages() { Map ret = new HashMap<>(); - definedPackagesMap.forEach((pkg, annotation) -> { - annotation.ifPresent(a -> ret.put(pkg, a)); + definedPackages.forEach((pkg, pkgInfo) -> { + pkgInfo.exportPackage().ifPresent(a -> ret.put(pkg, a)); }); return ret; } @@ -58,36 +59,37 @@ public class PackageTally { * Represents the classes for two package tallies that are deployed as a single unit. *

* ExportPackageAnnotations from this has precedence over the other. + * TODO: try using Map.merge (as in the functions below). Can't see how Maps.combine is any different. */ public PackageTally combine(PackageTally other) { - Map> map = Maps.combine(this.definedPackagesMap, other.definedPackagesMap, - (l, r) -> l.isPresent() ? l : r); + var definedPkgs = Maps.combine(this.definedPackages, other.definedPackages, PackageInfo::hasExportPackageOrElse); Set referencedPkgs = new HashSet<>(this.referencedPackagesUnfiltered); referencedPkgs.addAll(other.referencedPackagesUnfiltered); - return new PackageTally(map, referencedPkgs); + return new PackageTally(definedPkgs, referencedPkgs); } public static PackageTally combine(Collection packageTallies) { - Map> map = new HashMap<>(); + var definedPkgs = new HashMap(); Set referencedPkgs = new HashSet<>(); - for (PackageTally pt : packageTallies) { - pt.definedPackagesMap.forEach((k, v) -> map.merge(k, v, (l, r) -> l.isPresent() ? l : r)); - referencedPkgs.addAll(pt.referencedPackagesUnfiltered); + for (PackageTally tally : packageTallies) { + tally.definedPackages.forEach((pkg, info) -> definedPkgs.merge(pkg, info, PackageInfo::hasExportPackageOrElse)); + referencedPkgs.addAll(tally.referencedPackagesUnfiltered); } - return new PackageTally(map, referencedPkgs); + return new PackageTally(definedPkgs, referencedPkgs); } public static PackageTally fromAnalyzedClassFiles(Collection analyzedClassFiles) { - Map> map = new HashMap<>(); - Set referencedPkgs = new HashSet<>(); + var definedPkgs = new HashMap(); + var referencedPkgs = new HashSet(); - for (ClassFileMetaData metaData : analyzedClassFiles) { - String packageName = Packages.packageName(metaData.getName()); - map.merge(packageName, metaData.getExportPackage(), (l, r) -> l.isPresent() ? l : r); - metaData.getReferencedClasses().forEach(className -> referencedPkgs.add(Packages.packageName(className))); + for (ClassFileMetaData classData : analyzedClassFiles) { + var pkgName = classData.packageInfo().name(); + definedPkgs.merge(pkgName, classData.packageInfo(), PackageInfo::hasExportPackageOrElse); + classData.getReferencedClasses().forEach(className -> referencedPkgs.add(Packages.packageName(className))); } - return new PackageTally(map, referencedPkgs); + return new PackageTally(definedPkgs, referencedPkgs); } + } diff --git a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java index 9a7aade7ffb..11fe4a14d74 100644 --- a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java +++ b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/AnalyzeClassTest.java @@ -3,28 +3,27 @@ package com.yahoo.container.plugin.classanalysis; import com.yahoo.container.plugin.classanalysis.sampleclasses.Base; import com.yahoo.container.plugin.classanalysis.sampleclasses.ClassAnnotation; -import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.Derived; import com.yahoo.container.plugin.classanalysis.sampleclasses.DummyAnnotation; -import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleDummyAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.Fields; import com.yahoo.container.plugin.classanalysis.sampleclasses.Interface1; import com.yahoo.container.plugin.classanalysis.sampleclasses.Interface2; -import com.yahoo.container.plugin.classanalysis.sampleclasses.RecordWithOverride; -import com.yahoo.container.plugin.classanalysis.sampleclasses.SwitchStatement; +import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleAnnotation; +import com.yahoo.container.plugin.classanalysis.sampleclasses.InvisibleDummyAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.MethodAnnotation; import com.yahoo.container.plugin.classanalysis.sampleclasses.MethodInvocation; +import com.yahoo.container.plugin.classanalysis.sampleclasses.RecordWithOverride; +import com.yahoo.container.plugin.classanalysis.sampleclasses.SwitchStatement; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; import org.junit.jupiter.api.Test; import javax.security.auth.login.LoginException; -import java.awt.Image; +import java.awt.*; import java.awt.image.ImagingOpException; import java.awt.image.Kernel; import java.util.List; import java.util.Optional; -import java.util.Set; import static com.yahoo.container.plugin.classanalysis.TestUtilities.analyzeClass; import static com.yahoo.container.plugin.classanalysis.TestUtilities.classFile; @@ -133,7 +132,12 @@ public class AnalyzeClassTest { @Test void export_annotations_are_processed() { assertEquals(Optional.of(new ExportPackageAnnotation(3, 1, 4, "TEST_QUALIFIER-2")), - Analyze.analyzeClass(classFile("com.yahoo.container.plugin.classanalysis.sampleclasses.package-info")).getExportPackage()); + Analyze.analyzeClass(classFile("com.yahoo.container.plugin.classanalysis.sampleclasses.package-info")).getExportPackage()); + } + + @Test + void publicApi_annotations_are_processed() { + assertTrue(Analyze.analyzeClass(classFile("com.yahoo.container.plugin.classanalysis.sampleclasses.package-info")).isPublicApi()); } @Test diff --git a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java index d0d1db97c26..5f69032db17 100644 --- a/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java +++ b/bundle-plugin/src/test/java/com/yahoo/container/plugin/classanalysis/sampleclasses/package-info.java @@ -1,6 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. @ExportPackage(version = @Version(major = 3, minor = 1, micro = 4, qualifier = "TEST_QUALIFIER-2")) +@PublicApi package com.yahoo.container.plugin.classanalysis.sampleclasses; +import com.yahoo.api.annotations.PublicApi; import com.yahoo.osgi.annotation.ExportPackage; import com.yahoo.osgi.annotation.Version; -- cgit v1.2.3