diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml
index cad6e40b..e1faac58 100644
--- a/.github/workflows/promote.yml
+++ b/.github/workflows/promote.yml
@@ -36,7 +36,7 @@ jobs:
- name: Check Out
uses: actions/checkout@v4
- name: Set Up JFrog CLI
- uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.1.2
+ uses: jfrog/setup-jfrog-cli@ff5cb544114ffc152db9cea1cd3d5978d5074946 # v4.5.11
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Check Maven Central Sync Status
diff --git a/README.adoc b/README.adoc
index cb549f97..2c00258a 100644
--- a/README.adoc
+++ b/README.adoc
@@ -1,4 +1,4 @@
-:release-version: 0.0.43
+:release-version: 0.0.45
:checkstyle-version: 9.3
== Spring Java Format
diff --git a/pom.xml b/pom.xml
index c7e0ba80..5058125d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46
pom
Spring JavaFormat Build
Spring JavaFormat
diff --git a/samples/spring-javaformat-gradle-sample/build.gradle b/samples/spring-javaformat-gradle-sample/build.gradle
index 251a0478..cf53cc79 100644
--- a/samples/spring-javaformat-gradle-sample/build.gradle
+++ b/samples/spring-javaformat-gradle-sample/build.gradle
@@ -4,7 +4,7 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.44-SNAPSHOT")
+ classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.46-SNAPSHOT")
}
}
@@ -25,5 +25,5 @@ checkstyle {
}
dependencies {
- checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.44-SNAPSHOT")
+ checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.46-SNAPSHOT")
}
diff --git a/samples/spring-javaformat-maven-sample/pom.xml b/samples/spring-javaformat-maven-sample/pom.xml
index cf225184..22ac6ca4 100644
--- a/samples/spring-javaformat-maven-sample/pom.xml
+++ b/samples/spring-javaformat-maven-sample/pom.xml
@@ -8,7 +8,7 @@
0.0.1-SNAPSHOT
UTF-8
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml
index 9f08618a..566fc75f 100755
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml
@@ -2,7 +2,7 @@
@@ -22,7 +22,7 @@
id="io.spring.javaformat.eclipse"
download-size="0"
install-size="0"
- version="0.0.44.qualifier"
+ version="0.0.46.qualifier"
unpack="false"/>
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml
index 0393db0c..8781b88f 100755
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-eclipse
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
io.spring.javaformat.eclipse.feature
eclipse-feature
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml
index e3ad51fd..a7901f2c 100644
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml
@@ -3,7 +3,7 @@
Maven Integration for Eclipse (maven-eclipse-plugin support)
-
+
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product
index fc5cf2eb..542c8623 100644
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product
@@ -1,7 +1,7 @@
-
+
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml
index 7d8f71ce..73044003 100755
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-eclipse
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
io.spring.javaformat.eclipse.site
eclipse-repository
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF
index 4f9fbff4..6dc39cf8 100755
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF
@@ -7,7 +7,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: Spring Java Format Plugin Tests
Bundle-SymbolicName: io.spring.javaformat.eclipse.tests
Automatic-Module-Name: io.spring.javaformat.eclipse.tests
-Bundle-Version: 0.0.44.qualifier
+Bundle-Version: 0.0.46.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-ClassPath: .,
lib/assertj-core.jar,
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml
index bf8669b4..3e3b7156 100644
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-eclipse
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
io.spring.javaformat.eclipse.tests
eclipse-test-plugin
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF
index 46b89ccb..62909cb6 100644
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: Spring Java Format Plugin
Bundle-SymbolicName: io.spring.javaformat.eclipse;singleton:=true
Automatic-Module-Name: io.spring.javaformat.eclipse
-Bundle-Version: 0.0.44.qualifier
+Bundle-Version: 0.0.46.qualifier
Bundle-Activator: io.spring.javaformat.eclipse.Activator
Bundle-RequiredExecutionEnvironment: JavaSE-11
Require-Bundle: org.eclipse.ui,
diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml
index dec698d9..6c1fa6a7 100644
--- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml
+++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-eclipse
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
io.spring.javaformat.eclipse
eclipse-plugin
diff --git a/spring-javaformat-eclipse/pom.xml b/spring-javaformat-eclipse/pom.xml
index b0d1b674..1a2639c5 100644
--- a/spring-javaformat-eclipse/pom.xml
+++ b/spring-javaformat-eclipse/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-eclipse
pom
diff --git a/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml b/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml
index 21ea0f9b..93f26ee8 100644
--- a/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml
+++ b/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat-gradle
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
io.spring.javaformat
io.spring.javaformat.gradle.plugin
diff --git a/spring-javaformat-gradle/pom.xml b/spring-javaformat-gradle/pom.xml
index e3026aee..39880551 100644
--- a/spring-javaformat-gradle/pom.xml
+++ b/spring-javaformat-gradle/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-gradle
pom
diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml
index f6967ca0..0c7792a2 100644
--- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml
+++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-gradle
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-gradle-plugin
pom
diff --git a/spring-javaformat-intellij-idea/pom.xml b/spring-javaformat-intellij-idea/pom.xml
index 1daa8cad..42d82863 100644
--- a/spring-javaformat-intellij-idea/pom.xml
+++ b/spring-javaformat-intellij-idea/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-intellij-idea
pom
diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml
index a1e09a0e..f5581b69 100644
--- a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml
+++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-intellij-idea
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-intellij-idea-plugin
Spring JavaFormat IntelliJ IDEA Plugin
diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml
index 3e577cbd..bdbf48d4 100644
--- a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml
+++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-intellij-idea
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-intellij-idea-runtime
pom
diff --git a/spring-javaformat-maven/pom.xml b/spring-javaformat-maven/pom.xml
index 896f87b8..02900b22 100644
--- a/spring-javaformat-maven/pom.xml
+++ b/spring-javaformat-maven/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-maven
pom
diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml
index bdcb704c..100d5a83 100644
--- a/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml
+++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat-maven
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-maven-plugin
maven-plugin
diff --git a/spring-javaformat-vscode/pom.xml b/spring-javaformat-vscode/pom.xml
index e87f39f0..ed69c065 100644
--- a/spring-javaformat-vscode/pom.xml
+++ b/spring-javaformat-vscode/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-vscode
pom
diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json
index f991a7ab..7a1dbc61 100644
--- a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json
+++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "spring-javaformat-vscode-extension",
- "version": "0.0.44-SNAPSHOT",
+ "version": "0.0.46-SNAPSHOT",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "spring-javaformat-vscode-extension",
- "version": "0.0.44-SNAPSHOT",
+ "version": "0.0.46-SNAPSHOT",
"devDependencies": {
"@types/glob": "^8.0.1",
"@types/mocha": "^10.0.1",
diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json
index 290ae51f..0b7e7feb 100644
--- a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json
+++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json
@@ -2,7 +2,7 @@
"name": "spring-javaformat-vscode-extension",
"description": "Spring JavaFormat Visual Studio Code Extension",
"displayName": "Spring JavaFormat",
- "version": "0.0.44-SNAPSHOT",
+ "version": "0.0.46-SNAPSHOT",
"publisher": "io.spring.javaformat",
"engines": {
"vscode": "^1.75.0"
diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml b/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml
index 66239a95..afa9b39a 100644
--- a/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml
+++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat-vscode
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-vscode-extension
Spring JavaFormat Visual Studio Code Extension
diff --git a/spring-javaformat/pom.xml b/spring-javaformat/pom.xml
index e5991b91..c7815e7c 100644
--- a/spring-javaformat/pom.xml
+++ b/spring-javaformat/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat-build
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat
pom
diff --git a/spring-javaformat/spring-javaformat-checkstyle/pom.xml b/spring-javaformat/spring-javaformat-checkstyle/pom.xml
index 3ea8357e..709a2f6a 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/pom.xml
+++ b/spring-javaformat/spring-javaformat-checkstyle/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-checkstyle
Spring JavaFormat CheckStyle
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java
new file mode 100644
index 00000000..f0fc0d5e
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.spring.javaformat.checkstyle.check;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck;
+import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
+
+/**
+ * Spring variant of {@link AnnotationLocationCheck}.
+ *
+ * @author Phillip Webb
+ */
+public class SpringAnnotationLocationCheck extends AbstractCheck {
+
+ private static final Set JSPECIFY_ANNOTATION_NAMES = new HashSet<>(
+ Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked"));
+
+ @Override
+ public int[] getDefaultTokens() {
+ return new int[] { TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.PACKAGE_DEF,
+ TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF,
+ TokenTypes.VARIABLE_DEF, TokenTypes.RECORD_DEF, TokenTypes.COMPACT_CTOR_DEF, };
+ }
+
+ @Override
+ public int[] getAcceptableTokens() {
+ return new int[] { TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.PACKAGE_DEF,
+ TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF,
+ TokenTypes.VARIABLE_DEF, TokenTypes.ANNOTATION_DEF, TokenTypes.ANNOTATION_FIELD_DEF,
+ TokenTypes.RECORD_DEF, TokenTypes.COMPACT_CTOR_DEF, };
+ }
+
+ @Override
+ public int[] getRequiredTokens() {
+ return CommonUtil.EMPTY_INT_ARRAY;
+ }
+
+ @Override
+ public void visitToken(DetailAST ast) {
+ if (ast.getType() != TokenTypes.VARIABLE_DEF || ast.getParent().getType() == TokenTypes.OBJBLOCK) {
+ DetailAST node = ast.findFirstToken(TokenTypes.MODIFIERS);
+ node = (node != null) ? node : ast.findFirstToken(TokenTypes.ANNOTATIONS);
+ checkAnnotations(node, getExpectedAnnotationIndentation(node));
+ }
+ }
+
+ private int getExpectedAnnotationIndentation(DetailAST node) {
+ return node.getColumnNo();
+ }
+
+ private void checkAnnotations(DetailAST node, int correctIndentation) {
+ DetailAST annotation = node.getFirstChild();
+ while (annotation != null && annotation.getType() == TokenTypes.ANNOTATION) {
+ checkAnnotation(correctIndentation, annotation);
+ annotation = annotation.getNextSibling();
+ }
+ }
+
+ private void checkAnnotation(int correctIndentation, DetailAST annotation) {
+ String annotationName = getAnnotationName(annotation);
+ if (!isCorrectLocation(annotation) && !isJSpecifyAnnotation(annotationName)) {
+ log(annotation, AnnotationLocationCheck.MSG_KEY_ANNOTATION_LOCATION_ALONE, annotationName);
+ }
+ else if (annotation.getColumnNo() != correctIndentation && !hasNodeBefore(annotation)) {
+ log(annotation, AnnotationLocationCheck.MSG_KEY_ANNOTATION_LOCATION, annotationName,
+ annotation.getColumnNo(), correctIndentation);
+ }
+ }
+
+ private String getAnnotationName(DetailAST annotation) {
+ DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT);
+ if (identNode == null) {
+ identNode = annotation.findFirstToken(TokenTypes.DOT).findFirstToken(TokenTypes.IDENT);
+ }
+ return identNode.getText();
+ }
+
+ private boolean isCorrectLocation(DetailAST annotation) {
+ return !hasNodeBeside(annotation);
+ }
+
+ private boolean hasNodeBeside(DetailAST annotation) {
+ return hasNodeBefore(annotation) || hasNodeAfter(annotation);
+ }
+
+ private boolean hasNodeBefore(DetailAST annotation) {
+ int annotationLineNo = annotation.getLineNo();
+ DetailAST previousNode = annotation.getPreviousSibling();
+ return (previousNode != null) && (annotationLineNo == previousNode.getLineNo());
+ }
+
+ private boolean hasNodeAfter(DetailAST annotation) {
+ int annotationLineNo = annotation.getLineNo();
+ DetailAST nextNode = annotation.getNextSibling();
+ nextNode = (nextNode != null) ? nextNode : annotation.getParent().getNextSibling();
+ return annotationLineNo == nextNode.getLineNo();
+ }
+
+ private boolean isJSpecifyAnnotation(String annotationName) {
+ return JSPECIFY_ANNOTATION_NAMES.contains(annotationName);
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties
index a27f9263..cdea619e 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties
@@ -1,3 +1,5 @@
+annotation.location=Annotation ''{0}'' have incorrect indentation level {1}, expected level should be {2}.
+annotation.location.alone=Annotation ''{0}'' should be alone on line.
catch.singleLetter=Single letter catch variable (use "ex" instead).
catch.wideEye=''o_O'' catch variable (use "ex" instead).
header.unexpected=Unexpected header.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml
index fa6f8a64..4da52558 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml
@@ -24,10 +24,7 @@
-
-
-
+
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt
new file mode 100644
index 00000000..69174e4c
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt
@@ -0,0 +1 @@
++0 errors
\ No newline at end of file
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java
new file mode 100644
index 00000000..8799aae3
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.jspecify.annotations.Nullable;
+
+/**
+ * This is a valid example.
+ *
+ * @author Phillip Webb
+ */
+public class AnnotationOnNewLine {
+
+ @Override
+ public String toString() {
+ return "";
+ }
+
+ @Nullable String test1() {
+ return "";
+ }
+
+ @Override
+ @Nullable String test2() {
+ return "";
+ }
+
+ @Override
+ public @Nullable String test3() {
+ return "";
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/pom.xml b/spring-javaformat/spring-javaformat-config/pom.xml
index cf59a073..897d4d9a 100644
--- a/spring-javaformat/spring-javaformat-config/pom.xml
+++ b/spring-javaformat/spring-javaformat-config/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-config
Spring JavaFormat Config
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF
index abc2e727..b66f5efe 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Spring Formatter Eclipse Runtime JDK17
Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk17
-Bundle-Version: 0.0.44.qualifier
+Bundle-Version: 0.0.46.qualifier
Require-Bundle: org.eclipse.jdt.core;bundle-version="[1.0.0,10.0.0)",
org.eclipse.jface;bundle-version="[1.0.0,10.0.0)",
org.eclipse.jdt.core.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional,
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml
index 2eff5105..32c72950 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-eclipse-jdk17
eclipse-plugin
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF
index 24f373c1..a6aef027 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Spring Formatter Eclipse JDK8
Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk8
-Bundle-Version: 0.0.44.qualifier
+Bundle-Version: 0.0.46.qualifier
Require-Bundle: org.eclipse.jdt.core;bundle-version="[1.0.0,10.0.0)",
org.eclipse.jface;bundle-version="[1.0.0,10.0.0)",
org.eclipse.jdt.core.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional,
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml
index d2ce8030..3d3c8a4c 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-eclipse-jdk8
eclipse-plugin
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml
index 5e64f7b4..4b0ce32f 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-eclipse-jdt-jdk17
Spring JavaFormat Eclipse JDT JDK-17
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml
index 88f90cfc..0f557001 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-eclipse-jdt-jdk8
Spring JavaFormat Eclipse JDT JDK-8
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml
index 2a686bb6..eb7b4352 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml
@@ -5,7 +5,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-eclipse-rewriter
Spring JavaFormat Eclipse Rewriter
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml
index 9be91feb..a9bd4c45 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-eclipse-runtime
Spring JavaFormat Eclipse Runtime
diff --git a/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml b/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml
index d047564d..13723df1 100644
--- a/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-shaded
Spring JavaFormat Formatter Shaded
diff --git a/spring-javaformat/spring-javaformat-formatter-shader/pom.xml b/spring-javaformat/spring-javaformat-formatter-shader/pom.xml
index 6485c73e..2eea794d 100644
--- a/spring-javaformat/spring-javaformat-formatter-shader/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-shader/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-shader
Spring JavaFormat Formatter Shader
diff --git a/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml b/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml
index a2315b1f..97190e18 100644
--- a/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-test-support
Spring JavaFormat Formatter Test Support
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/pom.xml b/spring-javaformat/spring-javaformat-formatter-tests/pom.xml
index 6a0da60a..e43f5e4c 100644
--- a/spring-javaformat/spring-javaformat-formatter-tests/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-tests/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter-tests
Spring JavaFormat Formatter Tests
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java
index c01324c2..f2bebe0a 100644
--- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java
@@ -21,6 +21,7 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import io.spring.javaformat.config.JavaBaseline;
@@ -60,6 +61,7 @@ protected static Item[] items(String expectedOverride) {
addItem(items, javaBaseline, source, expected, config);
}
}
+ items.sort(Comparator.comparing(Item::getName));
return items.toArray(new Item[0]);
}
@@ -139,6 +141,10 @@ private JavaFormatConfig loadConfig(JavaBaseline javaBaseline, File configFile)
return JavaFormatConfig.of(javaBaseline, config.getIndentationStyle());
}
+ String getName() {
+ return this.source.getName();
+ }
+
public File getSource() {
return this.source;
}
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt
new file mode 100644
index 00000000..dbdb1f45
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt
@@ -0,0 +1,23 @@
+package example;
+
+import com.example.Nullable;
+
+/**
+ * Nullable.
+ *
+ * @author Phillip Webb
+ * @since 1.0.0
+ */
+public interface ExampleNullables {
+
+ @Override
+ @Nullable
+ String myMethod(String param);
+
+ @Override
+ public @Nullable String myPublicMethod(String param);
+
+ Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array,
+ @Nullable String @Nullable... varargs);
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt
new file mode 100644
index 00000000..053cbc13
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt
@@ -0,0 +1,22 @@
+package example;
+
+import org.jspecify.annotations.*;
+
+/**
+ * Nullable.
+ *
+ * @author Phillip Webb
+ * @since 1.0.0
+ */
+public interface ExampleNullables {
+
+ @Override
+ @Nullable String myMethod(String param);
+
+ @Override
+ public @Nullable String myPublicMethod(String param);
+
+ Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array,
+ @Nullable String @Nullable ... varargs);
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt
index b077cb5d..b3e8f925 100644
--- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt
@@ -16,6 +16,14 @@ public interface ExampleNullables {
@Override
public @Nullable String myPublicMethod(String param);
- Object myArrayMethod(@Nullable String @Nullable [] array, @Nullable String @Nullable ... varargs);
+ Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array,
+ @Nullable String @Nullable ... varargs);
+
+ default Object inBody() {
+ @Nullable Object[] args = new Object[length];
+ @Nullable List<@Nullable Object> list = new Object[length];
+ Object @Nullable [] moreArgs = new Object[length];
+ return args;
+ }
}
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt
new file mode 100644
index 00000000..011a2189
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt
@@ -0,0 +1,20 @@
+package example;
+
+import com.example.Nullable;
+
+/**
+ * Nullable.
+ *
+ * @author Phillip Webb
+ * @since 1.0.0
+ */
+public interface ExampleNullables {
+
+ @Override @Nullable String myMethod(String param);
+
+ @Override public @Nullable String myPublicMethod(String param);
+
+ Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable
+ String @Nullable ... varargs);
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt
new file mode 100644
index 00000000..11c65198
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt
@@ -0,0 +1,20 @@
+package example;
+
+import org.jspecify.annotations.*;
+
+/**
+ * Nullable.
+ *
+ * @author Phillip Webb
+ * @since 1.0.0
+ */
+public interface ExampleNullables {
+
+ @Override @Nullable String myMethod(String param);
+
+ @Override public @Nullable String myPublicMethod(String param);
+
+ Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable
+ String @Nullable ... varargs);
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt
index b2952241..acbefead 100644
--- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt
+++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt
@@ -14,7 +14,14 @@ public interface ExampleNullables {
@Override public @Nullable String myPublicMethod(String param);
- Object myArrayMethod(@Nullable String @Nullable [] array, @Nullable
+ Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable
String @Nullable ... varargs);
+ default Object inBody() {
+ @Nullable Object[] args = new Object[length];
+ @Nullable List<@Nullable Object> list = new Object[length];
+ Object @Nullable [] moreArgs = new Object[length];
+ return args;
+ }
+
}
diff --git a/spring-javaformat/spring-javaformat-formatter/pom.xml b/spring-javaformat/spring-javaformat-formatter/pom.xml
index c604551e..0f2ce215 100644
--- a/spring-javaformat/spring-javaformat-formatter/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter/pom.xml
@@ -6,7 +6,7 @@
io.spring.javaformat
spring-javaformat
- 0.0.44-SNAPSHOT
+ 0.0.46-SNAPSHOT
spring-javaformat-formatter
Spring JavaFormat Formatter
diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java
index 7d017570..645bf75d 100644
--- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java
+++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java
@@ -17,25 +17,38 @@
package io.spring.javaformat.formatter.jdk17.eclipse;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode;
import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor;
import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Annotation;
+import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.CompilationUnit;
import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.IExtendedModifier;
+import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ImportDeclaration;
import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.MethodDeclaration;
import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.SingleVariableDeclaration;
+import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.VariableDeclarationStatement;
import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter;
import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator;
import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager;
public class JSpecifyPreparator implements Preparator {
+ private static final String PACKAGE_NAME = "org.jspecify.annotations";
+
private static final Set ANNOTATION_NAMES = new HashSet<>(
Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked"));
+ private static final Set FULLY_QUALIFIED_ANNOTATION_NAMES = ANNOTATION_NAMES.stream()
+ .map((annotationName) -> PACKAGE_NAME + "." + annotationName)
+ .collect(Collectors.toSet());
+
@Override
public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) {
if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) {
@@ -48,17 +61,40 @@ private static class Vistor extends ASTVisitor {
private final TokenManager tokenManager;
+ private final Map fullyQualified = new HashMap<>();
+
Vistor(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
@Override
- @SuppressWarnings("unchecked")
- public boolean visit(MethodDeclaration node) {
- Annotation lastAnnotation = getLastAnnotation((List) node.modifiers());
- if (isJSpecifyAnnotation(lastAnnotation)) {
- this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter();
+ public boolean visit(CompilationUnit node) {
+ this.fullyQualified.clear();
+ return super.visit(node);
+ }
+
+ @Override
+ public boolean visit(ImportDeclaration node) {
+ String name = node.getName().toString();
+ if (name.equals(PACKAGE_NAME) || name.startsWith(PACKAGE_NAME)) {
+ Set annotationNames = (node.isOnDemand()) ? ANNOTATION_NAMES
+ : Collections.singleton(name.substring(name.lastIndexOf(".") + 1));
+ for (String annotationName : annotationNames) {
+ this.fullyQualified.put(annotationName, PACKAGE_NAME + "." + annotationName);
+ }
}
+ return super.visit(node);
+ }
+
+ @Override
+ public boolean visit(MethodDeclaration node) {
+ clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(VariableDeclarationStatement node) {
+ clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers());
return true;
}
@@ -74,6 +110,14 @@ public void endVisit(SingleVariableDeclaration node) {
}
}
+ @SuppressWarnings("unchecked")
+ private void clearLineBreaksIfHasJSpecifyAnnotation(List> modifiers) {
+ Annotation lastAnnotation = getLastAnnotation((List) modifiers);
+ if (isJSpecifyAnnotation(lastAnnotation)) {
+ this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter();
+ }
+ }
+
private Annotation getLastAnnotation(List extends IExtendedModifier> modifiers) {
Annotation annotation = null;
for (IExtendedModifier modifier : modifiers) {
@@ -86,7 +130,9 @@ private Annotation getLastAnnotation(List extends IExtendedModifier> modifiers
}
private boolean isJSpecifyAnnotation(Annotation annotation) {
- return (annotation != null) && ANNOTATION_NAMES.contains(annotation.getTypeName().toString());
+ String fullyQualifiedName = (annotation != null)
+ ? this.fullyQualified.get(annotation.getTypeName().toString()) : null;
+ return (fullyQualifiedName != null) && FULLY_QUALIFIED_ANNOTATION_NAMES.contains(fullyQualifiedName);
}
}
diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java
index 620b462f..4bc1aa0e 100644
--- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java
+++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java
@@ -17,25 +17,38 @@
package io.spring.javaformat.formatter.jdk8.eclipse;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTNode;
import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTVisitor;
import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.Annotation;
+import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.CompilationUnit;
import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.IExtendedModifier;
+import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ImportDeclaration;
import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.MethodDeclaration;
import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.SingleVariableDeclaration;
+import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.VariableDeclarationStatement;
import io.spring.javaformat.eclipse.jdt.jdk8.core.formatter.CodeFormatter;
import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Preparator;
import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.TokenManager;
public class JSpecifyPreparator implements Preparator {
+ private static final String PACKAGE_NAME = "org.jspecify.annotations";
+
private static final Set ANNOTATION_NAMES = new HashSet<>(
Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked"));
+ private static final Set FULLY_QUALIFIED_ANNOTATION_NAMES = ANNOTATION_NAMES.stream()
+ .map((annotationName) -> PACKAGE_NAME + "." + annotationName)
+ .collect(Collectors.toSet());
+
@Override
public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) {
if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) {
@@ -48,17 +61,40 @@ private static class Vistor extends ASTVisitor {
private final TokenManager tokenManager;
+ private final Map fullyQualified = new HashMap<>();
+
Vistor(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
@Override
- @SuppressWarnings("unchecked")
- public boolean visit(MethodDeclaration node) {
- Annotation lastAnnotation = getLastAnnotation((List) node.modifiers());
- if (isJSpecifyAnnotation(lastAnnotation)) {
- this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter();
+ public boolean visit(CompilationUnit node) {
+ this.fullyQualified.clear();
+ return super.visit(node);
+ }
+
+ @Override
+ public boolean visit(ImportDeclaration node) {
+ String name = node.getName().toString();
+ if (name.equals(PACKAGE_NAME) || name.startsWith(PACKAGE_NAME)) {
+ Set annotationNames = (node.isOnDemand()) ? ANNOTATION_NAMES
+ : Collections.singleton(name.substring(name.lastIndexOf(".") + 1));
+ for (String annotationName : annotationNames) {
+ this.fullyQualified.put(annotationName, PACKAGE_NAME + "." + annotationName);
+ }
}
+ return super.visit(node);
+ }
+
+ @Override
+ public boolean visit(MethodDeclaration node) {
+ clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(VariableDeclarationStatement node) {
+ clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers());
return true;
}
@@ -74,6 +110,14 @@ public void endVisit(SingleVariableDeclaration node) {
}
}
+ @SuppressWarnings("unchecked")
+ private void clearLineBreaksIfHasJSpecifyAnnotation(List> modifiers) {
+ Annotation lastAnnotation = getLastAnnotation((List) modifiers);
+ if (isJSpecifyAnnotation(lastAnnotation)) {
+ this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter();
+ }
+ }
+
private Annotation getLastAnnotation(List extends IExtendedModifier> modifiers) {
Annotation annotation = null;
for (IExtendedModifier modifier : modifiers) {
@@ -86,7 +130,9 @@ private Annotation getLastAnnotation(List extends IExtendedModifier> modifiers
}
private boolean isJSpecifyAnnotation(Annotation annotation) {
- return (annotation != null) && ANNOTATION_NAMES.contains(annotation.getTypeName().toString());
+ String fullyQualifiedName = (annotation != null)
+ ? this.fullyQualified.get(annotation.getTypeName().toString()) : null;
+ return (fullyQualifiedName != null) && FULLY_QUALIFIED_ANNOTATION_NAMES.contains(fullyQualifiedName);
}
}