84
85 Effective since value of an API element is computed as follows:
86 - if the given element has a @since tag in its javadoc, it is used
87 - in all other cases, return the effective since value of the enclosing element
88
89
90 Special Handling for preview method, as per JEP 12:
91 - When an element is still marked as preview, the `@since` should be the first JDK release where the element was added.
92 - If the element is no longer marked as preview, the `@since` should be the first JDK release where it was no longer preview.
93
94 note on legacy preview: Until JDK 14, the preview APIs were not marked in any machine-understandable way.
95 It was deprecated, and had a comment in the javadoc.
96 and the use of `@PreviewFeature` only became standard in JDK 17.
97 So the checker has an explicit knowledge of these preview elements.
98
99 note: The `<unique-Element-ID>` for methods looks like
100 `method: <erased-return-descriptor> <binary-name-of-enclosing-class>.<method-name>(<ParameterDescriptor>)`.
101 it is somewhat inspired from the VM Method Descriptors. But we use the erased return so that methods
102 that were later generified remain the same.
103
104 usage: the checker is run from a module specific test
105 `@run main SinceChecker <moduleName> [--exclude package1,package2 | --exclude package1 package2]`
106 */
107
108 public class SinceChecker {
109 private final Map<String, Set<String>> LEGACY_PREVIEW_METHODS = new HashMap<>();
110 private final Map<String, IntroducedIn> classDictionary = new HashMap<>();
111 private final JavaCompiler tool;
112 private int errorCount = 0;
113
114 // packages to skip during the test
115 private static final Set<String> EXCLUDE_LIST = new HashSet<>();
116
117 public static class IntroducedIn {
118 public String introducedPreview;
119 public String introducedStable;
120 }
121
122 public static void main(String[] args) throws Exception {
123 if (args.length == 0) {
124 throw new IllegalArgumentException("Test module not specified");
125 }
126 String moduleName = args[0];
127 boolean excludeFlag = false;
128
129 for (int i = 1; i < args.length; i++) {
130 if ("--exclude".equals(args[i])) {
131 excludeFlag = true;
132 continue;
133 }
134
135 if (excludeFlag) {
136 if (args[i].contains(",")) {
137 EXCLUDE_LIST.addAll(Arrays.asList(args[i].split(",")));
138 } else {
139 EXCLUDE_LIST.add(args[i]);
140 }
141 }
142 }
143
144 SinceChecker sinceCheckerTestHelper = new SinceChecker(moduleName);
145 sinceCheckerTestHelper.checkModule(moduleName);
146 }
147
148 private void error(String message) {
149 System.err.println(message);
150 errorCount++;
435 }
436 sinceVersion = effectiveSince.toString();
437 IntroducedIn mappedVersion = classDictionary.get(uniqueId);
438 if (mappedVersion == null) {
439 error("Element: " + uniqueId + " was not mapped");
440 return;
441 }
442 String realMappedVersion = null;
443 try {
444 realMappedVersion = isPreview(element, uniqueId, currentVersion) ?
445 mappedVersion.introducedPreview :
446 mappedVersion.introducedStable;
447 } catch (Exception e) {
448 error("For element " + element + "mappedVersion" + mappedVersion + " is null " + e);
449 }
450 String position = javadocHelper.getElementPosition(uniqueId);
451 checkEquals(position, sinceVersion, realMappedVersion, uniqueId);
452 }
453
454 private Version extractSinceVersionFromText(String documentation) {
455 Pattern pattern = Pattern.compile("@since\\s+(\\d+(?:\\.\\d+)?)");
456 Matcher matcher = pattern.matcher(documentation);
457 if (matcher.find()) {
458 String versionString = matcher.group(1);
459 try {
460 if (versionString.equals("1.0")) {
461 versionString = "1"; //ended up being necessary
462 } else if (versionString.startsWith("1.")) {
463 versionString = versionString.substring(2);
464 }
465 return Version.parse(versionString);
466 } catch (NumberFormatException ex) {
467 error("`@since` value that cannot be parsed: " + versionString);
468 return null;
469 }
470 } else {
471 return null;
472 }
473 }
474
|
84
85 Effective since value of an API element is computed as follows:
86 - if the given element has a @since tag in its javadoc, it is used
87 - in all other cases, return the effective since value of the enclosing element
88
89
90 Special Handling for preview method, as per JEP 12:
91 - When an element is still marked as preview, the `@since` should be the first JDK release where the element was added.
92 - If the element is no longer marked as preview, the `@since` should be the first JDK release where it was no longer preview.
93
94 note on legacy preview: Until JDK 14, the preview APIs were not marked in any machine-understandable way.
95 It was deprecated, and had a comment in the javadoc.
96 and the use of `@PreviewFeature` only became standard in JDK 17.
97 So the checker has an explicit knowledge of these preview elements.
98
99 note: The `<unique-Element-ID>` for methods looks like
100 `method: <erased-return-descriptor> <binary-name-of-enclosing-class>.<method-name>(<ParameterDescriptor>)`.
101 it is somewhat inspired from the VM Method Descriptors. But we use the erased return so that methods
102 that were later generified remain the same.
103
104 To help projects still in development, unsure of actual `@since` tag value, one may want to use token name instead of continuely
105 updating the current version since tags. For example, `@since LongRunningProjectName`. The option `--ignoreSince` maybe used to
106 ignore these tags (`--ignoreSince LongRunningProjectName`). Maybe be specified multiple times.
107
108 usage: the checker is run from a module specific test
109 `@run main SinceChecker <moduleName> [--ignoreSince <string>] [--exclude package1,package2 | --exclude package1 package2]`
110 */
111
112 public class SinceChecker {
113 private final Map<String, Set<String>> LEGACY_PREVIEW_METHODS = new HashMap<>();
114 private final Map<String, IntroducedIn> classDictionary = new HashMap<>();
115 private final JavaCompiler tool;
116 private int errorCount = 0;
117
118 // Ignored since tags
119 private static final Set<String> IGNORE_SINCE = new HashSet<>();
120 // Simply replace ignored since tags with the latest version
121 private static final Version IGNORE_VERSION = Version.parse(Integer.toString(Runtime.version().major()));
122
123 // packages to skip during the test
124 private static final Set<String> EXCLUDE_LIST = new HashSet<>();
125
126 public static class IntroducedIn {
127 public String introducedPreview;
128 public String introducedStable;
129 }
130
131 public static void main(String[] args) throws Exception {
132 if (args.length == 0) {
133 throw new IllegalArgumentException("Test module not specified");
134 }
135 String moduleName = args[0];
136 boolean excludeFlag = false;
137
138 for (int i = 1; i < args.length; i++) {
139 if ("--ignoreSince".equals(args[i])) {
140 i++;
141 IGNORE_SINCE.add("@since " + args[i]);
142 }
143 else if ("--exclude".equals(args[i])) {
144 excludeFlag = true;
145 continue;
146 }
147
148 if (excludeFlag) {
149 if (args[i].contains(",")) {
150 EXCLUDE_LIST.addAll(Arrays.asList(args[i].split(",")));
151 } else {
152 EXCLUDE_LIST.add(args[i]);
153 }
154 }
155 }
156
157 SinceChecker sinceCheckerTestHelper = new SinceChecker(moduleName);
158 sinceCheckerTestHelper.checkModule(moduleName);
159 }
160
161 private void error(String message) {
162 System.err.println(message);
163 errorCount++;
448 }
449 sinceVersion = effectiveSince.toString();
450 IntroducedIn mappedVersion = classDictionary.get(uniqueId);
451 if (mappedVersion == null) {
452 error("Element: " + uniqueId + " was not mapped");
453 return;
454 }
455 String realMappedVersion = null;
456 try {
457 realMappedVersion = isPreview(element, uniqueId, currentVersion) ?
458 mappedVersion.introducedPreview :
459 mappedVersion.introducedStable;
460 } catch (Exception e) {
461 error("For element " + element + "mappedVersion" + mappedVersion + " is null " + e);
462 }
463 String position = javadocHelper.getElementPosition(uniqueId);
464 checkEquals(position, sinceVersion, realMappedVersion, uniqueId);
465 }
466
467 private Version extractSinceVersionFromText(String documentation) {
468 for (String ignoreSince : IGNORE_SINCE) {
469 if (documentation.contains(ignoreSince)) {
470 return IGNORE_VERSION;
471 }
472 }
473 Pattern pattern = Pattern.compile("@since\\s+(\\d+(?:\\.\\d+)?)");
474 Matcher matcher = pattern.matcher(documentation);
475 if (matcher.find()) {
476 String versionString = matcher.group(1);
477 try {
478 if (versionString.equals("1.0")) {
479 versionString = "1"; //ended up being necessary
480 } else if (versionString.startsWith("1.")) {
481 versionString = versionString.substring(2);
482 }
483 return Version.parse(versionString);
484 } catch (NumberFormatException ex) {
485 error("`@since` value that cannot be parsed: " + versionString);
486 return null;
487 }
488 } else {
489 return null;
490 }
491 }
492
|