{
+
+ /**
+ * First paragraph.
+ *
+ * Second paragraph contains an asterisk in a code element: {@code *}.
+ * @since 1.0
+ */
+ public void test() {
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodHasEarlierSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodHasEarlierSince.java
new file mode 100644
index 00000000..d23d74ee
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodHasEarlierSince.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Javadoc with an earlier since tag on a method.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+public class JavadocMethodHasEarlierSince {
+
+ /**
+ * Some method.
+ * @since 1.2.3
+ */
+ public void someMethod() {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java
index 9f22ace8..c9afd407 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonJavadocComment.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonJavadocComment.java
new file mode 100644
index 00000000..047b2a05
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonJavadocComment.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Example with non javadoc comments.
+ *
+ * @author Phillip Webb
+ */
+public class JavadocNonJavadocComment {
+
+ /* (non-Javadoc)
+ * Example.
+ */
+ public void one() {
+ }
+
+ /**
+ * (non-Javadoc).
+ */
+ public void two() {
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java
index 58e914d3..4f0f2fde 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -25,7 +25,7 @@ class JavadocNonPublicSince {
/**
* Inner class.
*
- * @since 1.2.3
+ * @since 1.2.4
*/
private static class Inner {
diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FormatterOption.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideAnnotation.java
similarity index 72%
rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FormatterOption.java
rename to spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideAnnotation.java
index 5b2504ef..b79a5a85 100644
--- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FormatterOption.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideAnnotation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -14,18 +14,23 @@
* limitations under the License.
*/
-package io.spring.javaformat.formatter;
-
/**
- * Options that can be used to configure a {@link Formatter}.
+ * Javadoc with a good since tag.
*
* @author Phillip Webb
+ * @since 1.2.3
*/
-public enum FormatterOption {
+public @interface JavadocNonPublicSinceInsideAnnotation {
/**
- * Show Eclipse NLS warnings.
+ * Inner enum.
+ *
+ * @since 1.2.4
*/
- SHOW_NLS_WARNINGS
+ enum Inner {
+
+ FOO
+
+ }
}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java
index a8fa5f47..c0e4b412 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -25,7 +25,7 @@ public interface JavadocNonPublicSinceInsideInterface {
/**
* Inner enum.
*
- * @since 1.2.3
+ * @since 1.2.4
*/
enum Inner {
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocSoundtrack.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocSoundtrack.java
new file mode 100644
index 00000000..846bf48d
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocSoundtrack.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Valid Javadoc.
+ *
+ * @param this is a valid param
+ * @author Phillip Webb
+ * @soundtrack Gina G - Ooh Aah Just A Little Bit
+ */
+public class JavadocSoundtrack {
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java
index 21d30add..6584ef36 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -46,4 +46,34 @@ public void test2(String something) {
public String test3(String something) throws RuntimeException {
}
+ /**
+ * Class with a numeric date since.
+ * @since 28.12.2003
+ */
+ public class NumericDateSince {
+
+ /**
+ * Method with version-based since.
+ * @since 1.3.0
+ */
+ public void versionSince() {
+ }
+
+ }
+
+ /**
+ * Class with an alphanumeric date since.
+ * @since 16 April 2001
+ */
+ public class AlphanumericDateSince {
+
+ /**
+ * Method with version-based since.
+ * @since 1.3.0
+ */
+ public void versionSince() {
+ }
+
+ }
+
}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java
index c4f17b30..5e82a117 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java
index 4e621d28..9ab33a37 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java
index 86807333..cfb42294 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java
index d1f83089..b8246fee 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java
index 4208b212..5468bb48 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java
index 059bb564..473fa096 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java
index 24f4da47..61350fe8 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java
index d2f5cde9..2c874d0d 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java
index c9cab5fa..54864d72 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaSwitch.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaSwitch.java
new file mode 100644
index 00000000..55640621
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaSwitch.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017-present 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 java.util.function.Function;
+
+/**
+ * Lambda in a switch statement.
+ *
+ * @author Josef Reichardt
+ */
+public class LambdaSwitch {
+
+ private void sayHello(String[] args) {
+ Function getText = (cnt) -> "Number of args: " + cnt;
+ String message = switch (args.length) {
+ case 0 -> "No arg";
+ case 1 -> "One arg";
+ default -> getText.apply(args.length);
+ };
+ System.out.println(message);
+ }
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java
index b5f9b616..df215545 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java
index 465f92c0..768488e7 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceSpaces.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceSpaces.java
new file mode 100644
index 00000000..0e69080a
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceSpaces.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Leading whitepace expects only tabs.
+ *
+ * @author Phillip Webb
+ */
+public class LeadingWhitespaceSpaces {
+
+ /**
+ * Comments are ignored.
+ */
+ public void hello() {
+ System.out.println("World");
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabs.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabs.java
new file mode 100644
index 00000000..53d64c19
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabs.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Leading whitepace expects only tabs.
+ *
+ * @author Phillip Webb
+ */
+public class LeadingWhitespaceTabs {
+
+ /**
+ * Comments are ignored.
+ */
+ public void hello() {
+ System.out.println("World");
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java
new file mode 100644
index 00000000..21a2311a
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Leading whitepace with a text block.
+ *
+ * @author Phillip Webb
+ */
+public class LeadingWhitespaceTabsAndTextBlock {
+
+ /**
+ * Comments are ignored.
+ */
+ public void hello() {
+ System.out.println(""""
+ Hello
+ World!""");
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java
index 9271ba92..0db3e04c 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java
index 2bffbcae..b44ad87b 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithOverride.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithOverride.java
new file mode 100644
index 00000000..6a74b3b7
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithOverride.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Good visibility because, while class is final, protected methods are
+ * annotated with {@code @Override}.
+ *
+ * @author Andy Wilkinson
+ */
+public final class MethodVisibilityFinalClassWithOverride {
+
+ @Override
+ protected void good() {
+ }
+
+ @Override
+ protected static void goodStatic() {
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithProtectedMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithProtectedMethod.java
new file mode 100644
index 00000000..7452e21f
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithProtectedMethod.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Bad visibility because class is final.
+ *
+ * @author Andy Wilkinson
+ */
+public final class MethodVisibilityFinalClassWithProtectedMethod {
+
+ protected void bad() {
+ }
+
+ protected static void badStatic() {
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java
index cf10eb76..262a258f 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java
index 75d5b080..c6377f3d 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityProtectedWithPublicMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityProtectedWithPublicMethod.java
new file mode 100644
index 00000000..fe36ec8c
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityProtectedWithPublicMethod.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Good visibility because class is protected.
+ *
+ * @author Phillip Webb
+ */
+protected class MethodVisibilityProtectedWithPublicMethod {
+
+ MethodVisibilityPackagePrivateWithPublicMethod() {
+ }
+
+ public void bad() {
+ }
+
+ public static void badStatic() {
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java
index 2be96a19..c4b8d3b3 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -15,7 +15,7 @@
*/
/**
- * Bad visibility because of public method.
+ * Good visibility because of {@code @Override} annotation.
*
* @author Phillip Webb
*/
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java
index d41dbaee..8f9bb820 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java
index 2e80c229..436c72a4 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java
index aa8fe05d..556214ab 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNonNull.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNonNull.java
new file mode 100644
index 00000000..870a40e9
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNonNull.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present 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 javax.annotation.Nonnull;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+/**
+ * JSpecify's NonNull annotation should be used.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityBannedNonNull {
+
+ public void method(@Nonnull String one, @NonNull String two) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNullable.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNullable.java
new file mode 100644
index 00000000..61d918d1
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNullable.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-present 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 javax.annotation.Nullable;
+
+/**
+ * JSpecify's Nullable annotation should be used.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityBannedNullable {
+
+ public void method(@Nullable String one) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingFieldType.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingFieldType.java
new file mode 100644
index 00000000..a54069ef
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingFieldType.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-present 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;
+
+/**
+ * {@code @Nullable} should appear immediately before the parameter type.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityNullableNotPrecedingFieldType {
+
+ private @Nullable static String field = null;
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingParameterType.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingParameterType.java
new file mode 100644
index 00000000..bd55d9d2
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingParameterType.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-present 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;
+
+/**
+ * {@code @Nullable} should appear immediately before the parameter type.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityNullableNotPrecedingParameterType {
+
+ public String method(@Nullable final String arg) {
+ return "result";
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingReturnType.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingReturnType.java
new file mode 100644
index 00000000..9b9b8a4e
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingReturnType.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-present 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;
+
+/**
+ * {@code @Nullable} should appear immediately before the return type.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityNullableNotPrecedingReturnType {
+
+ @Nullable public String method() {
+ return "result";
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableOnSeparateLine.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableOnSeparateLine.java
new file mode 100644
index 00000000..b18ee10a
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableOnSeparateLine.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017-present 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;
+
+/**
+ * {@code @Nullable} should appear immediately before the return type.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityNullableOnSeparateLine {
+
+ @Nullable
+ public String method() {
+ return "result";
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityValid.java
new file mode 100644
index 00000000..e0ea5cca
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityValid.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017-present 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 java.util.Collections;
+import java.util.Map;
+
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Valid use of nullability annotations.
+ *
+ * @author Andy Wilkinson
+ */
+public class NullabilityValid {
+
+ private @Nullable String field;
+
+ public NullabilityValid(@Nullable String arg, final @Nullable String anotherArg) {
+
+ }
+
+ public @Nullable String publicMethod() {
+ return "result";
+ }
+
+ @Nullable String packagePrivateMethod() {
+ return "result";
+ }
+
+ public Map genericReturnType() {
+ return Collections.emptyMap();
+ }
+
+ void genericParameter(Map<@Nullable ? extends String, @Nullable String> arg) {
+
+ }
+
+ void parameter(@Nullable String arg) {
+
+ }
+
+ void finalParameter(final @Nullable String arg) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java
index 0c2f80ad..59f7dc88 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java
index c9ee62bc..6814ed2f 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java
index d64f298e..d72c300b 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -935,8 +935,8 @@ public void setMainApplicationClass(Class> mainApplicationClass) {
/**
* Returns whether this {@link SpringApplication} is running within a web environment.
* @return {@code true} if running within a web environment, otherwise {@code false}.
- * @see #setWebEnvironment(boolean)
* @deprecated since 2.0.0 in favor of {@link #getWebApplicationType()}
+ * @see #setWebEnvironment(boolean)
*/
@Deprecated
public boolean isWebEnvironment() {
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java
index 355cfad5..afd0926d 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java
index bc73a067..9eb48eb9 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java
index 8371a02e..3a30c31a 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java
index 1fedecbe..99c43de5 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java
index 61a4ab20..6414b748 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -24,7 +24,9 @@ public class TernaryInIf {
public void test() {
boolean a = true;
boolean b = false;
- if ((a != b) ? true : false) {
+ int c = 1;
+ int d = 2;
+ if ((a != b) ? d < c : c >= d) {
System.out.println("OK");
}
}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java
index 46641514..1bef3bee 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -24,7 +24,9 @@ public class TernaryInWhile {
public void test() {
boolean a = true;
boolean b = false;
- while ((a != b) ? true : false) {
+ int c = 1;
+ int d = 2;
+ while ((a != b) ? d < c : c >= d) {
System.out.println("OK");
}
}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java
index 942b1bce..36e22af3 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java
index 69fc4218..cbd7ce9e 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java
index 42f842c3..f9f490ee 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TryWithResources.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TryWithResources.java
new file mode 100644
index 00000000..c68396dc
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TryWithResources.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * This is a valid example.
+ *
+ * @author Phillip Webb
+ */
+public class TryWithResources {
+
+ public void test() {
+ try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {
+ System.out.println(session);
+ }
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java
index da4f0436..e14319f1 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArray.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArray.java
new file mode 100644
index 00000000..2d25cfa7
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArray.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Whitespace is expected before {@code []} when @Nullable.
+ *
+ * @author Andy Wilkinson
+ */
+public class WhitespaceNullableArray {
+
+ void bytes(int @Nullable [] elements) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArrayElements.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArrayElements.java
new file mode 100644
index 00000000..6e23b7fb
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArrayElements.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Whitespace is expected before {@code type[]} when @Nullable.
+ *
+ * @author Andy Wilkinson
+ */
+public class WhitespaceNullableArrayElements {
+
+ void bytes(@Nullable int[] elements) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableVarargs.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableVarargs.java
new file mode 100644
index 00000000..1b4eaeae
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableVarargs.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Whitespace is expected before ... when @Nullable.
+ *
+ * @author Andy Wilkinson
+ */
+public class WhitespaceNullableVarargs {
+
+ void bytes(int @Nullable ... elements) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceVarargs.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceVarargs.java
new file mode 100644
index 00000000..2a962abe
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceVarargs.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * Whitespace is not expected before {@code ...}.
+ *
+ * @author Andy Wilkinson
+ */
+public class WhitespaceVarargs {
+
+ void bytes(int ... elements) {
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/nopackageinfo/NoPackageInfo.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/nopackageinfo/NoPackageInfo.java
new file mode 100644
index 00000000..5ae26280
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/nopackageinfo/NoPackageInfo.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-present 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 nopackageinfo;
+
+/**
+ * A class in a package with no {@code package-info.java} file.
+ *
+ * @author Andy Wilkinson
+ */
+class NoPackageInfo {
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java
index b426e3ba..039f3f05 100644
--- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this foil except in compliance with the License.
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info.java
new file mode 100644
index 00000000..e69de29b
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java
new file mode 100644
index 00000000..cdc31f8c
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * This is an annotation with a legal name. Only test classes must
+ * have a name that ends with {@code Tests}.
+ *
+ * @author Andy Wilkinson
+ */
+public @interface AnnotationEndingInTest {
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java
new file mode 100644
index 00000000..d79b6453
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * This is an interface with a legal name. Only test classes must
+ * have a name that ends with {@code Tests}.
+ *
+ * @author Andy Wilkinson
+ */
+public interface InterfaceEndingInTest {
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTest.java
new file mode 100644
index 00000000..a042f613
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * This is a test with the wrong name.
+ *
+ * @author Phillip Webb
+ */
+public class NamedTest {
+
+}
diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTests.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTests.java
new file mode 100644
index 00000000..423428e5
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTests.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017-present 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.
+ */
+
+/**
+ * This is a test with the correct name.
+ *
+ * @author Phillip Webb
+ */
+public class NamedTests {
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/pom.xml b/spring-javaformat/spring-javaformat-config/pom.xml
new file mode 100644
index 00000000..e984a073
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/pom.xml
@@ -0,0 +1,15 @@
+
+
+ 4.0.0
+
+ io.spring.javaformat
+ spring-javaformat
+ 0.0.48-SNAPSHOT
+
+ spring-javaformat-config
+ Spring JavaFormat Config
+
+ ${basedir}/../..
+
+
diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/DefaultJavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/DefaultJavaFormatConfig.java
new file mode 100644
index 00000000..d2b5ee8c
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/DefaultJavaFormatConfig.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017-present 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.config;
+
+/**
+ * Default {@link JavaFormatConfig} implementation used when no config file is found.
+ *
+ * @author Phillip Webb
+ */
+class DefaultJavaFormatConfig implements JavaFormatConfig {
+
+ private final JavaBaseline javaBaseline;
+
+ private final IndentationStyle indentationStyle;
+
+ DefaultJavaFormatConfig(JavaBaseline javaBaseline, IndentationStyle indentationStyle) {
+ this.javaBaseline = javaBaseline;
+ this.indentationStyle = indentationStyle;
+ }
+
+ @Override
+ public JavaBaseline getJavaBaseline() {
+ return this.javaBaseline;
+ }
+
+ @Override
+ public IndentationStyle getIndentationStyle() {
+ return this.indentationStyle;
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/IndentationStyle.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/IndentationStyle.java
new file mode 100644
index 00000000..f6e2144d
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/IndentationStyle.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017-present 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.config;
+
+/**
+ * Indentation styles that can be used.
+ *
+ * @author Phillip Webb
+ */
+public enum IndentationStyle {
+
+ /**
+ * Indent with tabs.
+ */
+ TABS,
+
+ /**
+ * Indent with spaces.
+ */
+ SPACES
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java
new file mode 100644
index 00000000..a27c3df0
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017-present 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.config;
+
+/**
+ * Java JDK baseline version expected be used when formatting.
+ *
+ * @author Phillip Webb
+ */
+public enum JavaBaseline {
+
+ /**
+ * Use JDK 8+ compatible formatter.
+ */
+ V8,
+
+ /**
+ * Use JDK 17+ or higher compatible formatter.
+ */
+ V17
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java
new file mode 100644
index 00000000..23bf45c8
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017-present 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.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+
+/**
+ * Support for the {@code .springjavaformatconfig} file that can be used to apply settings
+ * on a per-project basis.
+ *
+ * @author Phillip Webb
+ */
+public interface JavaFormatConfig {
+
+ /**
+ * The default {@link JavaFormatConfig}.
+ */
+ JavaFormatConfig DEFAULT = of(JavaBaseline.V17, IndentationStyle.TABS);
+
+ /**
+ * Java JDK baseline version expected be used when formatting.
+ * @return the JDK version
+ */
+ JavaBaseline getJavaBaseline();
+
+ /**
+ * Return the indentation style that should be used with the project.
+ * @return the indentation style
+ */
+ IndentationStyle getIndentationStyle();
+
+ /**
+ * Find and load a {@code .springjavaformatconfig} by searching from the given file.
+ * @param path the file or directory to search from
+ * @return a loaded {@link JavaFormatConfig} or {@link #DEFAULT} if no
+ * {@code .springjavaformatconfig} file is found
+ */
+ static JavaFormatConfig findFrom(Path path) {
+ return findFrom((path != null) ? path.toFile() : (File) null);
+ }
+
+ /**
+ * Find and load a {@code .springjavaformatconfig} by searching from the given file.
+ * @param file the file or directory to search from
+ * @return a loaded {@link JavaFormatConfig} or {@link #DEFAULT} if no
+ * {@code .springjavaformatconfig} file is found
+ */
+ static JavaFormatConfig findFrom(File file) {
+ if (file != null && file.isFile()) {
+ return findFrom(file.getParentFile());
+ }
+ try {
+ while (file != null) {
+ File candidate = new File(file, ".springjavaformatconfig");
+ if (candidate.exists() && candidate.isFile()) {
+ return load(candidate);
+ }
+ file = file.getParentFile();
+ }
+ }
+ catch (Exception ex) {
+ }
+ return DEFAULT;
+ }
+
+ /**
+ * Load a {@link JavaFormatConfig} from the given file.
+ * @param file the file to load
+ * @return the loaded config
+ */
+ static JavaFormatConfig load(File file) {
+ try {
+ return PropertiesJavaFormatConfig.load(file);
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ /**
+ * Load a {@link JavaFormatConfig} from the given input stream.
+ * @param inputStream the input stream to load
+ * @return the loaded config
+ */
+ static JavaFormatConfig load(InputStream inputStream) {
+ try {
+ return PropertiesJavaFormatConfig.load(inputStream);
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ /**
+ * Factory method to create a {@link JavaFormatConfig} with specific settings.
+ * @param javaBaseline The baseline JDK version
+ * @param indentationStyle the indentation style
+ * @return a {@link JavaFormatConfig} instance
+ */
+ static JavaFormatConfig of(JavaBaseline javaBaseline, IndentationStyle indentationStyle) {
+ return new DefaultJavaFormatConfig(javaBaseline, indentationStyle);
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/PropertiesJavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/PropertiesJavaFormatConfig.java
new file mode 100644
index 00000000..d631312d
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/PropertiesJavaFormatConfig.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017-present 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.config;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * {@link JavaFormatConfig} backed by a properties file.
+ *
+ * @author Phillip Webb
+ */
+class PropertiesJavaFormatConfig implements JavaFormatConfig {
+
+ private final Properties properties;
+
+ PropertiesJavaFormatConfig(Properties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public JavaBaseline getJavaBaseline() {
+ Object value = this.properties.get("java-baseline");
+ return (value != null) ? JavaBaseline.valueOf("V" + value.toString().toUpperCase().trim())
+ : DEFAULT.getJavaBaseline();
+ }
+
+ @Override
+ public IndentationStyle getIndentationStyle() {
+ Object value = this.properties.get("indentation-style");
+ return (value != null) ? IndentationStyle.valueOf(value.toString().toUpperCase().trim())
+ : DEFAULT.getIndentationStyle();
+ }
+
+ static JavaFormatConfig load(File file) throws IOException {
+ try (InputStream inputStream = new FileInputStream(file)) {
+ return load(inputStream);
+ }
+ }
+
+ static JavaFormatConfig load(InputStream inputStream) throws IOException {
+ Properties properties = new Properties();
+ properties.load(inputStream);
+ return new PropertiesJavaFormatConfig(properties);
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java b/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java
new file mode 100644
index 00000000..2c702617
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-present 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.config;
+
+import java.util.Properties;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link PropertiesJavaFormatConfig}.
+ *
+ * @author Phillip Webb
+ */
+class PropertiesJavaFormatConfigTests {
+
+ @Test
+ void getJavaBaselineWhenNoPropertyReturnsJava11() {
+ Properties properties = new Properties();
+ PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties);
+ assertThat(config.getJavaBaseline()).isEqualTo(JavaBaseline.V17);
+ }
+
+ @Test
+ void getJavaBaselineWhenPropertyReturnsPropertyValue() {
+ Properties properties = new Properties();
+ properties.setProperty("java-baseline", "8");
+ PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties);
+ assertThat(config.getJavaBaseline()).isEqualTo(JavaBaseline.V8);
+ }
+
+ @Test
+ void getIndentationStyleWhenNoPropertyReturnsJava11() {
+ Properties properties = new Properties();
+ PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties);
+ assertThat(config.getIndentationStyle()).isEqualTo(IndentationStyle.TABS);
+ }
+
+ @Test
+ void getIndentationStyleWhenPropertyReturnsPropertyValue() {
+ Properties properties = new Properties();
+ properties.setProperty("indentation-style", "spaces");
+ PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties);
+ assertThat(config.getIndentationStyle()).isEqualTo(IndentationStyle.SPACES);
+ }
+
+}
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
new file mode 100644
index 00000000..5e2e9099
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+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.48.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,
+ org.eclipse.jface.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional,
+ org.eclipse.jface.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional,
+ org.eclipse.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional
+Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/build.properties b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/build.properties
similarity index 100%
rename from spring-javaformat/spring-javaformat-formatter-eclipse-runtime/build.properties
rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/build.properties
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml
new file mode 100644
index 00000000..0e73c0e4
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml
@@ -0,0 +1,213 @@
+
+
+ 4.0.0
+
+ io.spring.javaformat
+ spring-javaformat
+ 0.0.48-SNAPSHOT
+
+ spring-javaformat-formatter-eclipse-jdk17
+ eclipse-plugin
+ Spring JavaFormat Eclipse JDK-17
+
+ ${basedir}/../..
+ org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source
+
+
+
+ Eclipse Public License, Version 1.0
+ https://www.eclipse.org/legal/epl-v10.html
+
+
+
+
+ eclipse-jdk17
+ p2
+ ${eclipse.jdk17.repository}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ empty-javadoc-jar
+ package
+
+ jar
+
+
+ javadoc
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ io.spring.javaformat
+ spring-javaformat-formatter-eclipse-rewriter
+ ${project.version}
+
+
+ ant-contrib
+ ant-contrib
+ ${ant-contrib.version}
+
+
+ ant
+ ant
+
+
+
+
+ org.apache.ant
+ ant-nodeps
+ ${ant.version}
+
+
+
+
+ rewrite-bytecode
+ package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+ repackage-source
+ package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-packaging-plugin
+
+ false
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+
+
+ org.eclipse.tycho
+ target-platform-configuration
+
+
+ org.eclipse.tycho
+ tycho-versions-plugin
+
+
+ update-eclipse-version
+ initialize
+
+ update-eclipse-metadata
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ unpack-dependencies
+
+ unpack-dependencies
+
+ prepare-package
+
+ ${project.build.outputDirectory}
+ META-INF/*,**.dll,**.so,**.java
+ ${sourceartifacts}
+
+
+
+ unpack-source-dependencies
+
+ unpack-dependencies
+
+ prepare-package
+
+ ${project.build.directory}/sources
+ ${sourceartifacts}
+
+
+
+
+
+ com.github.wvengen
+ proguard-maven-plugin
+
+
+ reduce-eclipse-runtime
+ package
+
+ proguard
+
+
+ false
+
+ ${java.home}/jmods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ io.spring.javaformat
+ spring-javaformat-formatter-eclipse-rewriter
+ ${project.version}
+ provided
+
+
+
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF
similarity index 72%
rename from spring-javaformat/spring-javaformat-formatter-eclipse-runtime/META-INF/MANIFEST.MF
rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF
index b6666bd7..3c5dbb8b 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/META-INF/MANIFEST.MF
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF
@@ -1,12 +1,12 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
-Bundle-Name: Spring Formatter Eclipse Runtime
-Bundle-SymbolicName: spring-javaformat-formatter-eclipse-runtime
-Bundle-Version: 0.0.21.qualifier
+Bundle-Name: Spring Formatter Eclipse JDK8
+Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk8
+Bundle-Version: 0.0.48.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,
org.eclipse.jface.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional,
org.eclipse.jface.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional,
org.eclipse.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/build.properties b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/build.properties
new file mode 100755
index 00000000..45d47043
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = target/classes
+bin.includes = META-INF/,\
+ .,\
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml
new file mode 100644
index 00000000..0e52bf06
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml
@@ -0,0 +1,213 @@
+
+
+ 4.0.0
+
+ io.spring.javaformat
+ spring-javaformat
+ 0.0.48-SNAPSHOT
+
+ spring-javaformat-formatter-eclipse-jdk8
+ eclipse-plugin
+ Spring JavaFormat Eclipse JDK-8
+
+ ${basedir}/../..
+ org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source
+
+
+
+ Eclipse Public License, Version 1.0
+ https://www.eclipse.org/legal/epl-v10.html
+
+
+
+
+ eclipse-jdk8
+ p2
+ ${eclipse.jdk8.repository}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ empty-javadoc-jar
+ package
+
+ jar
+
+
+ javadoc
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ io.spring.javaformat
+ spring-javaformat-formatter-eclipse-rewriter
+ ${project.version}
+
+
+ ant-contrib
+ ant-contrib
+ ${ant-contrib.version}
+
+
+ ant
+ ant
+
+
+
+
+ org.apache.ant
+ ant-nodeps
+ ${ant.version}
+
+
+
+
+ rewrite-bytecode
+ package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+ repackage-source
+ package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-packaging-plugin
+
+ false
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+
+
+ org.eclipse.tycho
+ target-platform-configuration
+
+
+ org.eclipse.tycho
+ tycho-versions-plugin
+
+
+ update-eclipse-version
+ initialize
+
+ update-eclipse-metadata
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ unpack-dependencies
+
+ unpack-dependencies
+
+ prepare-package
+
+ ${project.build.outputDirectory}
+ META-INF/*,**.dll,**.so,**.java
+ ${sourceartifacts}
+
+
+
+ unpack-source-dependencies
+
+ unpack-dependencies
+
+ prepare-package
+
+ ${project.build.directory}/sources
+ ${sourceartifacts}
+
+
+
+
+
+ com.github.wvengen
+ proguard-maven-plugin
+
+
+ reduce-eclipse-runtime
+ package
+
+ proguard
+
+
+ false
+
+ ${java.home}/jmods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ io.spring.javaformat
+ spring-javaformat-formatter-eclipse-rewriter
+ ${project.version}
+ provided
+
+
+
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml
similarity index 78%
rename from spring-javaformat/spring-javaformat-formatter-eclipse/pom.xml
rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml
index f298f7e4..9aef9a9a 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml
@@ -6,18 +6,18 @@
io.spring.javaformat
spring-javaformat
- 0.0.21-SNAPSHOT
+ 0.0.48-SNAPSHOT
- spring-javaformat-formatter-eclipse
- Spring JavaFormat Eclipse
+ spring-javaformat-formatter-eclipse-jdt-jdk17
+ Spring JavaFormat Eclipse JDT JDK-17
${basedir}/../..
io.spring.javaformat
- spring-javaformat-formatter-eclipse-runtime
- 0.0.21-SNAPSHOT
+ spring-javaformat-formatter-eclipse-jdk17
+ ${project.version}
true
@@ -48,16 +48,16 @@
- io.spring.javaformat:spring-javaformat-formatter-eclipse-runtime
+ io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk17
- org/eclipse/jdt/internal/formatter/**
+ org/eclipse/jdt/**
- org.eclipse.jdt.internal.formatter
- io.spring.javaformat.formatter.eclipse
+ org.eclipse.jdt
+ io.spring.javaformat.eclipse.jdt.jdk17
false
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
similarity index 94%
rename from spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
index ad16d3f2..a2664b72 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -107,8 +107,9 @@ protected void prepareWraps(int kind) {
}
private void applyPreparators(Phase preWrapping, int kind, ASTNode astRoot, TokenManager tokenManager) {
- this.preparators.stream().filter((preparator) -> preparator.getPhase() == preWrapping)
- .forEach((preparator) -> preparator.apply(kind, tokenManager, astRoot));
+ this.preparators.stream()
+ .filter((preparator) -> preparator.getPhase() == preWrapping)
+ .forEach((preparator) -> preparator.apply(kind, tokenManager, astRoot));
}
@SuppressWarnings("unchecked")
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
similarity index 95%
rename from spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
index 23b52527..bfd16b37 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -54,7 +54,7 @@ enum Phase {
/**
* Apply the preparator after wrapping.
*/
- POST_WRAPPING;
+ POST_WRAPPING
}
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml
new file mode 100644
index 00000000..30a2af39
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+ io.spring.javaformat
+ spring-javaformat
+ 0.0.48-SNAPSHOT
+
+ spring-javaformat-formatter-eclipse-jdt-jdk8
+ Spring JavaFormat Eclipse JDT JDK-8
+
+ ${basedir}/../..
+
+
+
+ io.spring.javaformat
+ spring-javaformat-formatter-eclipse-jdk8
+ ${project.version}
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-source
+ package
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk8
+
+ org/eclipse/jdt/**
+
+
+
+
+
+ org.eclipse.jdt
+ io.spring.javaformat.eclipse.jdt.jdk8
+
+
+ false
+ true
+ true
+
+
+
+
+
+
+
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
new file mode 100644
index 00000000..a2664b72
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017-present 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 org.eclipse.jdt.internal.formatter;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
+import org.eclipse.jdt.internal.formatter.Preparator.Phase;
+
+/**
+ * Extended version of {@link DefaultCodeFormatter} that allows additional
+ * {@link Preparator preparators} to be used.
+ *
+ * @author Phillip Webb
+ */
+public class ExtendedCodeFormatter extends DefaultCodeFormatter {
+
+ private static boolean useLegacyTokenize = false;
+
+ private final List preparators = new ArrayList<>();
+
+ public ExtendedCodeFormatter() {
+ super();
+ }
+
+ public ExtendedCodeFormatter(DefaultCodeFormatterOptions defaultCodeFormatterOptions, Map options) {
+ super(defaultCodeFormatterOptions, options);
+ }
+
+ public ExtendedCodeFormatter(DefaultCodeFormatterOptions options) {
+ super(options);
+ }
+
+ public ExtendedCodeFormatter(Map options) {
+ super(options);
+ }
+
+ protected void addPreparator(Preparator preparator) {
+ this.preparators.add(preparator);
+ }
+
+ @Override
+ protected void tokenizeSource(int kind) {
+ if (useLegacyTokenize) {
+ legacyTokenizeSource(kind);
+ return;
+ }
+ try {
+ super.tokenizeSource(kind);
+ }
+ catch (NoSuchMethodError ex) {
+ useLegacyTokenize = true;
+ legacyTokenizeSource(kind);
+ }
+ }
+
+ private void legacyTokenizeSource(int kind) {
+ this.tokens.clear();
+ long sourceLevel = CompilerOptions.versionToJdkLevel(this.sourceLevel);
+ Scanner scanner = new Scanner(true, false, false, sourceLevel, null, null, false);
+ scanner.setSource(this.sourceArray);
+ scanner.fakeInModule = (kind & K_MODULE_INFO) != 0;
+ while (true) {
+ try {
+ int tokenType = scanner.getNextToken();
+ if (tokenType == TerminalTokens.TokenNameEOF) {
+ break;
+ }
+ Token token = Token.fromCurrent(scanner, tokenType);
+ this.tokens.add(token);
+ }
+ catch (InvalidInputException ex) {
+ Token token = Token.fromCurrent(scanner, TerminalTokens.TokenNameNotAToken);
+ this.tokens.add(token);
+ }
+ }
+ }
+
+ @Override
+ protected void prepareWraps(int kind) {
+ ASTNode astRoot = getField("astRoot", ASTNode.class);
+ TokenManager tokenManager = getField("tokenManager", TokenManager.class);
+ applyPreparators(Phase.PRE_WRAPPING, kind, astRoot, tokenManager);
+ super.prepareWraps(kind);
+ applyPreparators(Phase.POST_WRAPPING, kind, astRoot, tokenManager);
+ }
+
+ private void applyPreparators(Phase preWrapping, int kind, ASTNode astRoot, TokenManager tokenManager) {
+ this.preparators.stream()
+ .filter((preparator) -> preparator.getPhase() == preWrapping)
+ .forEach((preparator) -> preparator.apply(kind, tokenManager, astRoot));
+ }
+
+ @SuppressWarnings("unchecked")
+ private T getField(String name, Class type) {
+ try {
+ Field field = DefaultCodeFormatter.class.getDeclaredField(name);
+ field.setAccessible(true);
+ return (T) field.get(this);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
new file mode 100644
index 00000000..bfd16b37
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017-present 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 org.eclipse.jdt.internal.formatter;
+
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.formatter.CodeFormatter;
+
+/**
+ * Strategy interface used by {@link ExtendedCodeFormatter} to allow additional code
+ * formatting before wrapping.
+ *
+ * @author Phillip Webb
+ */
+public interface Preparator {
+
+ default Phase getPhase() {
+ return Phase.POST_WRAPPING;
+ }
+
+ /**
+ * Apply the preparator.
+ * @param kind the format kind (see
+ * {@link CodeFormatter#format(int, String, org.eclipse.jface.text.IRegion[], int, String)}
+ * for details)
+ * @param tokenManager the token manager
+ * @param astRoot the AST root node
+ */
+ void apply(int kind, TokenManager tokenManager, ASTNode astRoot);
+
+ /**
+ * The phase where the {@link Preparator} should be applied.
+ */
+ enum Phase {
+
+ /**
+ * Apply the preparator before wrapping.
+ */
+ PRE_WRAPPING,
+
+ /**
+ * Apply the preparator after wrapping.
+ */
+ POST_WRAPPING
+
+ }
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
new file mode 100644
index 00000000..6878ca6f
--- /dev/null
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
@@ -0,0 +1,1688 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2020 Mateusz Matela and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Mateusz Matela - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Mateusz Matela - [formatter] follow up bug for comments - https://bugs.eclipse.org/458208
+ *******************************************************************************/
+package org.eclipse.jdt.internal.formatter.linewrap;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
+
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.Annotation;
+import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
+import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
+import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
+import org.eclipse.jdt.core.dom.ArrayInitializer;
+import org.eclipse.jdt.core.dom.AssertStatement;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CatchClause;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
+import org.eclipse.jdt.core.dom.ConditionalExpression;
+import org.eclipse.jdt.core.dom.ConstructorInvocation;
+import org.eclipse.jdt.core.dom.CreationReference;
+import org.eclipse.jdt.core.dom.DoStatement;
+import org.eclipse.jdt.core.dom.EnhancedForStatement;
+import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
+import org.eclipse.jdt.core.dom.EnumDeclaration;
+import org.eclipse.jdt.core.dom.ExportsDirective;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.ExpressionMethodReference;
+import org.eclipse.jdt.core.dom.FieldAccess;
+import org.eclipse.jdt.core.dom.FieldDeclaration;
+import org.eclipse.jdt.core.dom.ForStatement;
+import org.eclipse.jdt.core.dom.IExtendedModifier;
+import org.eclipse.jdt.core.dom.IfStatement;
+import org.eclipse.jdt.core.dom.InfixExpression;
+import org.eclipse.jdt.core.dom.InfixExpression.Operator;
+import org.eclipse.jdt.core.dom.LambdaExpression;
+import org.eclipse.jdt.core.dom.MemberValuePair;
+import org.eclipse.jdt.core.dom.MethodDeclaration;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.NormalAnnotation;
+import org.eclipse.jdt.core.dom.OpensDirective;
+import org.eclipse.jdt.core.dom.PackageDeclaration;
+import org.eclipse.jdt.core.dom.ParameterizedType;
+import org.eclipse.jdt.core.dom.ProvidesDirective;
+import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
+import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
+import org.eclipse.jdt.core.dom.SuperFieldAccess;
+import org.eclipse.jdt.core.dom.SuperMethodInvocation;
+import org.eclipse.jdt.core.dom.SuperMethodReference;
+import org.eclipse.jdt.core.dom.SwitchExpression;
+import org.eclipse.jdt.core.dom.SwitchStatement;
+import org.eclipse.jdt.core.dom.ThisExpression;
+import org.eclipse.jdt.core.dom.TryStatement;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
+import org.eclipse.jdt.core.dom.TypeMethodReference;
+import org.eclipse.jdt.core.dom.TypeParameter;
+import org.eclipse.jdt.core.dom.UnionType;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.core.dom.WhileStatement;
+import org.eclipse.jdt.core.formatter.CodeFormatter;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
+import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
+import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment;
+import org.eclipse.jdt.internal.formatter.Token;
+import org.eclipse.jdt.internal.formatter.Token.WrapMode;
+import org.eclipse.jdt.internal.formatter.Token.WrapPolicy;
+import org.eclipse.jdt.internal.formatter.TokenManager;
+import org.eclipse.jdt.internal.formatter.TokenTraverser;
+import org.eclipse.jface.text.IRegion;
+
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOLON;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMA;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameDOT;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEQUAL;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameIdentifier;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLBRACE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLESS;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLPAREN;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameOR;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameQUESTION;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameRBRACE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameRPAREN;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameSEMICOLON;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameStringLiteral;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameenum;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameextends;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameimplements;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamenew;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamesuper;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamethis;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamethrows;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameto;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamewhile;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamewith;
+
+public class WrapPreparator extends ASTVisitor {
+
+ // @formatter:off
+
+ /**
+ * Helper for common handling of all expressions that should be treated the same as
+ * {@link FieldAccess}
+ */
+ private static class FieldAccessAdapter {
+ final Expression accessExpression;
+
+ public FieldAccessAdapter(Expression expression) {
+ this.accessExpression = expression;
+ }
+
+ public static boolean isFieldAccess(ASTNode expr) {
+ return expr instanceof FieldAccess || expr instanceof QualifiedName || expr instanceof ThisExpression
+ || expr instanceof SuperFieldAccess;
+ }
+
+ public Expression getExpression() {
+ if (this.accessExpression instanceof FieldAccess) {
+ return ((FieldAccess) this.accessExpression).getExpression();
+ }
+ if (this.accessExpression instanceof QualifiedName) {
+ return ((QualifiedName) this.accessExpression).getQualifier();
+ }
+ if (this.accessExpression instanceof ThisExpression) {
+ return ((ThisExpression) this.accessExpression).getQualifier();
+ }
+ if (this.accessExpression instanceof SuperFieldAccess) {
+ return ((SuperFieldAccess) this.accessExpression).getQualifier();
+ }
+ throw new AssertionError();
+ }
+
+ public int getIdentifierIndex(TokenManager tm) {
+ if (this.accessExpression instanceof FieldAccess) {
+ return tm.firstIndexIn(((FieldAccess) this.accessExpression).getName(), TokenNameIdentifier);
+ }
+ if (this.accessExpression instanceof QualifiedName) {
+ return tm.firstIndexIn(((QualifiedName) this.accessExpression).getName(), TokenNameIdentifier);
+ }
+ if (this.accessExpression instanceof ThisExpression) {
+ return tm.lastIndexIn(this.accessExpression, TokenNamethis);
+ }
+ if (this.accessExpression instanceof SuperFieldAccess) {
+ return tm.lastIndexIn(this.accessExpression, TokenNamesuper);
+ }
+ throw new AssertionError();
+ }
+ }
+
+ private static final Map OPERATOR_PRECEDENCE;
+ private static final Map> OPERATOR_WRAPPING_OPTION;
+ private static final Map> OPERATOR_WRAP_BEFORE_OPTION;
+ static {
+ HashMap precedence = new HashMap<>();
+ HashMap> wrappingOption = new HashMap<>();
+ HashMap> wrapBeforeOption = new HashMap<>();
+ for (Operator op : Arrays.asList(Operator.TIMES, Operator.DIVIDE, Operator.REMAINDER)) {
+ precedence.put(op, 1);
+ wrappingOption.put(op, o -> o.alignment_for_multiplicative_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_multiplicative_operator);
+ }
+ for (Operator op : Arrays.asList(Operator.PLUS, Operator.MINUS)) {
+ precedence.put(op, 2);
+ wrappingOption.put(op, o -> o.alignment_for_additive_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_additive_operator);
+ }
+ for (Operator op : Arrays.asList(Operator.LEFT_SHIFT, Operator.RIGHT_SHIFT_SIGNED,
+ Operator.RIGHT_SHIFT_UNSIGNED)) {
+ precedence.put(op, 3);
+ wrappingOption.put(op, o -> o.alignment_for_shift_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_shift_operator);
+ }
+ for (Operator op : Arrays.asList(Operator.LESS, Operator.GREATER, Operator.LESS_EQUALS,
+ Operator.GREATER_EQUALS)) {
+ precedence.put(op, 4);
+ wrappingOption.put(op, o -> o.alignment_for_relational_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_relational_operator);
+ }
+ for (Operator op : Arrays.asList(Operator.EQUALS, Operator.NOT_EQUALS)) {
+ precedence.put(op, 5);
+ wrappingOption.put(op, o -> o.alignment_for_relational_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_relational_operator);
+ }
+
+ precedence.put(Operator.AND, 6);
+ precedence.put(Operator.XOR, 7);
+ precedence.put(Operator.OR, 8);
+ for (Operator op : Arrays.asList(Operator.AND, Operator.XOR, Operator.OR)) {
+ wrappingOption.put(op, o -> o.alignment_for_bitwise_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_bitwise_operator);
+ }
+
+ precedence.put(Operator.CONDITIONAL_AND, 9);
+ precedence.put(Operator.CONDITIONAL_OR, 10);
+ for (Operator op : Arrays.asList(Operator.CONDITIONAL_AND, Operator.CONDITIONAL_OR)) {
+ wrappingOption.put(op, o -> o.alignment_for_logical_operator);
+ wrapBeforeOption.put(op, o -> o.wrap_before_logical_operator);
+ }
+ // ternary and assignment operators not relevant to infix expressions
+
+ OPERATOR_PRECEDENCE = Collections.unmodifiableMap(precedence);
+ OPERATOR_WRAPPING_OPTION = Collections.unmodifiableMap(wrappingOption);
+ OPERATOR_WRAP_BEFORE_OPTION = Collections.unmodifiableMap(wrapBeforeOption);
+ }
+
+ /** Penalty multiplier for wraps that are preferred */
+ private final static float PREFERRED = 7f / 8;
+
+ final TokenManager tm;
+ final DefaultCodeFormatterOptions options;
+ final int kind;
+
+ final Aligner aligner;
+
+ /*
+ * temporary values used when calling {@link #handleWrap(int)} to avoid ArrayList
+ * initialization and long lists of parameters
+ */
+ private List wrapIndexes = new ArrayList<>();
+ /**
+ * Indexes for wraps that shouldn't happen but should be indented if cannot be removed
+ */
+ private List secondaryWrapIndexes = new ArrayList<>();
+ private List wrapPenalties = new ArrayList<>();
+ private int wrapParentIndex = -1;
+ private int wrapGroupEnd = -1;
+
+ private int currentDepth = 0;
+
+ public WrapPreparator(TokenManager tokenManager, DefaultCodeFormatterOptions options, int kind) {
+ this.tm = tokenManager;
+ this.options = options;
+ this.kind = kind;
+
+ this.aligner = new Aligner(this.tm, this.options);
+ }
+
+ @Override
+ public boolean preVisit2(ASTNode node) {
+ this.currentDepth++;
+
+ assert this.wrapIndexes.isEmpty() && this.secondaryWrapIndexes.isEmpty() && this.wrapPenalties.isEmpty();
+ assert this.wrapParentIndex == -1 && this.wrapGroupEnd == -1;
+
+ boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0;
+ if (isMalformed) {
+ this.tm.addDisableFormatTokenPair(this.tm.firstTokenIn(node, -1), this.tm.lastTokenIn(node, -1));
+ }
+ return !isMalformed;
+ }
+
+ @Override
+ public void postVisit(ASTNode node) {
+ this.currentDepth--;
+ }
+
+ @Override
+ public boolean visit(PackageDeclaration node) {
+ handleAnnotations(node.annotations(), this.options.alignment_for_annotations_on_package);
+ return true;
+ }
+
+ @Override
+ public boolean visit(NormalAnnotation node) {
+ int lParen = this.tm.firstIndexAfter(node.getTypeName(), TokenNameLPAREN);
+ int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_annotation);
+
+ handleArguments(node.values(), this.options.alignment_for_arguments_in_annotation);
+ return true;
+ }
+
+ @Override
+ public boolean visit(SingleMemberAnnotation node) {
+ int lParen = this.tm.firstIndexAfter(node.getTypeName(), TokenNameLPAREN);
+ int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_annotation);
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type);
+
+ Type superclassType = node.getSuperclassType();
+ if (superclassType != null) {
+ this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1);
+ this.wrapGroupEnd = this.tm.lastIndexIn(superclassType, -1);
+ this.wrapIndexes.add(this.tm.firstIndexBefore(superclassType, TokenNameextends));
+ this.wrapIndexes.add(this.tm.firstIndexIn(superclassType, -1));
+ handleWrap(this.options.alignment_for_superclass_in_type_declaration, PREFERRED);
+ }
+
+ List superInterfaceTypes = node.superInterfaceTypes();
+ if (!superInterfaceTypes.isEmpty()) {
+ int implementsToken = node.isInterface() ? TokenNameextends : TokenNameimplements;
+ this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1);
+ this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), implementsToken));
+ prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1);
+ handleWrap(this.options.alignment_for_superinterfaces_in_type_declaration, PREFERRED);
+ }
+
+ prepareElementsList(node.typeParameters(), TokenNameCOMMA, TokenNameLESS);
+ handleWrap(this.options.alignment_for_type_parameters);
+
+ this.aligner.handleAlign(node.bodyDeclarations());
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(AnnotationTypeDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type);
+ this.aligner.handleAlign(node.bodyDeclarations());
+ return true;
+ }
+
+ @Override
+ public boolean visit(AnnotationTypeMemberDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_method);
+ return true;
+ }
+
+ @Override
+ public boolean visit(AnonymousClassDeclaration node) {
+ this.aligner.handleAlign(node.bodyDeclarations());
+ return true;
+ }
+
+ @Override
+ public boolean visit(RecordDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type);
+
+ int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
+ List components = node.recordComponents();
+ int rParen = this.tm.firstIndexAfter(
+ components.isEmpty() ? node.getName() : components.get(components.size() - 1), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_record_declaration);
+
+ if (!components.isEmpty()) {
+ int wrappingOption = this.options.alignment_for_record_components;
+ this.wrapGroupEnd = this.tm.lastIndexIn(components.get(components.size() - 1), -1);
+ handleArguments(components, wrappingOption);
+ }
+
+ List superInterfaceTypes = node.superInterfaceTypes();
+ if (!superInterfaceTypes.isEmpty()) {
+ this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1);
+ this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), TokenNameimplements));
+ prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1);
+ handleWrap(this.options.alignment_for_superinterfaces_in_record_declaration, PREFERRED);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(MethodDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_method);
+
+ if (!node.isCompactConstructor()) {
+ int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
+ int rParen = node.getBody() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN)
+ : this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_declaration);
+ }
+
+ List parameters = node.parameters();
+ Type receiverType = node.getReceiverType();
+ if (!parameters.isEmpty() || receiverType != null) {
+ if (receiverType != null) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(receiverType, -1));
+ }
+ int wrappingOption = node.isConstructor() ? this.options.alignment_for_parameters_in_constructor_declaration
+ : this.options.alignment_for_parameters_in_method_declaration;
+ this.wrapGroupEnd = this.tm
+ .lastIndexIn(parameters.isEmpty() ? receiverType : parameters.get(parameters.size() - 1), -1);
+ handleArguments(parameters, wrappingOption);
+ }
+
+ List exceptionTypes = node.thrownExceptionTypes();
+ if (!exceptionTypes.isEmpty()) {
+ int wrappingOption = node.isConstructor()
+ ? this.options.alignment_for_throws_clause_in_constructor_declaration
+ : this.options.alignment_for_throws_clause_in_method_declaration;
+ if ((wrappingOption & Alignment.M_INDENT_ON_COLUMN) == 0) {
+ this.wrapParentIndex = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
+ }
+ prepareElementsList(exceptionTypes, TokenNameCOMMA, TokenNameRPAREN);
+ // instead of the first exception type, wrap the "throws" token
+ this.wrapIndexes.set(0, this.tm.firstIndexBefore(exceptionTypes.get(0), TokenNamethrows));
+ handleWrap(wrappingOption, 0.5f);
+ }
+
+ if (!node.isConstructor()) {
+ this.wrapParentIndex = this.tm.findFirstTokenInLine(this.tm.firstIndexIn(node.getName(), -1));
+ while (this.tm.get(this.wrapParentIndex).isComment()) {
+ this.wrapParentIndex++;
+ }
+ List typeParameters = node.typeParameters();
+ if (!typeParameters.isEmpty()) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(typeParameters.get(0), -1));
+ }
+ if (node.getReturnType2() != null) {
+ int returTypeIndex = this.tm.firstIndexIn(node.getReturnType2(), -1);
+ if (returTypeIndex != this.wrapParentIndex) {
+ this.wrapIndexes.add(returTypeIndex);
+ }
+ }
+ this.wrapIndexes.add(this.tm.firstIndexIn(node.getName(), -1));
+ this.wrapGroupEnd = this.tm.lastIndexIn(node.getName(), -1);
+ handleWrap(this.options.alignment_for_method_declaration);
+ }
+
+ prepareElementsList(node.typeParameters(), TokenNameCOMMA, TokenNameLESS);
+ handleWrap(this.options.alignment_for_type_parameters);
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(EnumDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type);
+
+ List enumConstants = node.enumConstants();
+ int constantsEnd = -1;
+ if (!enumConstants.isEmpty()) {
+ for (EnumConstantDeclaration constant : enumConstants) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(constant, -1));
+ }
+ this.wrapParentIndex = (this.options.alignment_for_enum_constants & Alignment.M_INDENT_ON_COLUMN) > 0
+ ? this.tm.firstIndexBefore(enumConstants.get(0), TokenNameLBRACE)
+ : this.tm.firstIndexIn(node, TokenNameenum);
+ this.wrapGroupEnd = constantsEnd = this.tm.lastIndexIn(enumConstants.get(enumConstants.size() - 1), -1);
+ handleWrap(this.options.alignment_for_enum_constants, node);
+ }
+
+ if (!this.options.join_wrapped_lines) {
+ // preserve a line break between the last comma and semicolon
+ int commaIndex = -1;
+ int i = constantsEnd > 0 ? constantsEnd : this.tm.firstIndexAfter(node.getName(), TokenNameLBRACE);
+ while (++i < this.tm.size()) {
+ Token t = this.tm.get(i);
+ if (t.isComment()) {
+ continue;
+ }
+ if (t.tokenType == TokenNameCOMMA) {
+ commaIndex = i;
+ continue;
+ }
+ if (t.tokenType == TokenNameSEMICOLON && commaIndex >= 0
+ && this.tm.countLineBreaksBetween(this.tm.get(commaIndex), t) == 1) {
+ t.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, commaIndex, 0));
+ }
+ break;
+ }
+ }
+
+ List superInterfaceTypes = node.superInterfaceTypes();
+ if (!superInterfaceTypes.isEmpty()) {
+ this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1);
+ this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), TokenNameimplements));
+ prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1);
+ handleWrap(this.options.alignment_for_superinterfaces_in_enum_declaration, PREFERRED);
+ }
+
+ this.aligner.handleAlign(node.bodyDeclarations());
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(EnumConstantDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_enum_constant);
+
+ int lParen = this.tm.firstIndexAfter(node.getName(), -1);
+ while (this.tm.get(lParen).isComment()) {
+ lParen++;
+ }
+ if (this.tm.get(lParen).tokenType == TokenNameLPAREN) {
+ int rParen = node.getAnonymousClassDeclaration() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN)
+ : this.tm.firstIndexBefore(node.getAnonymousClassDeclaration(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_enum_constant_declaration);
+ }
+
+ handleArguments(node.arguments(), this.options.alignment_for_arguments_in_enum_constant);
+ AnonymousClassDeclaration anonymousClass = node.getAnonymousClassDeclaration();
+ if (anonymousClass != null) {
+ forceContinuousWrapping(anonymousClass, this.tm.firstIndexIn(node.getName(), -1));
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(Block node) {
+ this.aligner.handleAlign(node);
+ return true;
+ }
+
+ @Override
+ public boolean visit(MethodInvocation node) {
+ // Method patched based on
+ // https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/189391/4/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
+ int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
+ int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation);
+
+ handleArguments(node.arguments(), this.options.alignment_for_arguments_in_method_invocation);
+ handleTypeArguments(node.typeArguments());
+
+ boolean isInvocationChainRoot = !(node.getParent() instanceof MethodInvocation)
+ || node.getLocationInParent() != MethodInvocation.EXPRESSION_PROPERTY;
+ if (isInvocationChainRoot) {
+ Expression expression = node;
+ MethodInvocation invocation = node;
+ while (expression instanceof MethodInvocation) {
+ invocation = (MethodInvocation) expression;
+ expression = invocation.getExpression();
+ if (expression != null) {
+ this.wrapIndexes.add(this.tm.firstIndexBefore(invocation.getName(), TokenNameDOT));
+ this.secondaryWrapIndexes.add(this.tm.firstIndexIn(invocation.getName(), TokenNameIdentifier));
+ }
+ }
+ Collections.reverse(this.wrapIndexes);
+ expression = (expression != null) ? expression : invocation;
+ this.wrapParentIndex = this.tm.lastIndexIn(expression, -1);
+ if ((this.options.alignment_for_selector_in_method_invocation & Alignment.M_INDENT_ON_COLUMN) == 0) {
+ this.wrapParentIndex = this.tm.firstIndexIn(expression, -1);
+ }
+ this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+ handleWrap(this.options.alignment_for_selector_in_method_invocation);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(SuperMethodInvocation node) {
+ int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
+ int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation);
+
+ handleArguments(node.arguments(), this.options.alignment_for_arguments_in_method_invocation);
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(ClassInstanceCreation node) {
+ int lParen = this.tm.firstIndexAfter(node.getType(), TokenNameLPAREN);
+ int rParen = node.getAnonymousClassDeclaration() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN)
+ : this.tm.firstIndexBefore(node.getAnonymousClassDeclaration(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation);
+
+ AnonymousClassDeclaration anonymousClass = node.getAnonymousClassDeclaration();
+ if (anonymousClass != null) {
+ forceContinuousWrapping(anonymousClass, this.tm.firstIndexIn(node, TokenNamenew));
+ }
+
+ int wrappingOption = node.getExpression() != null
+ ? this.options.alignment_for_arguments_in_qualified_allocation_expression
+ : this.options.alignment_for_arguments_in_allocation_expression;
+ handleArguments(node.arguments(), wrappingOption);
+
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(ConstructorInvocation node) {
+ int lParen = node.arguments().isEmpty() ? this.tm.lastIndexIn(node, TokenNameLPAREN)
+ : this.tm.firstIndexBefore((ASTNode) node.arguments().get(0), TokenNameLPAREN);
+ int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation);
+
+ handleArguments(node.arguments(), this.options.alignment_for_arguments_in_explicit_constructor_call);
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(SuperConstructorInvocation node) {
+ int lParen = node.arguments().isEmpty() ? this.tm.lastIndexIn(node, TokenNameLPAREN)
+ : this.tm.firstIndexBefore((ASTNode) node.arguments().get(0), TokenNameLPAREN);
+ int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation);
+
+ handleArguments(node.arguments(), this.options.alignment_for_arguments_in_explicit_constructor_call);
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(FieldAccess node) {
+ handleFieldAccess(node);
+ return true;
+ }
+
+ @Override
+ public boolean visit(QualifiedName node) {
+ handleFieldAccess(node);
+ return true;
+ }
+
+ @Override
+ public boolean visit(ThisExpression node) {
+ handleFieldAccess(node);
+ return true;
+ }
+
+ @Override
+ public boolean visit(SuperFieldAccess node) {
+ handleFieldAccess(node);
+ return true;
+ }
+
+ private void handleFieldAccess(Expression node) {
+ boolean isAccessChainRoot = !FieldAccessAdapter.isFieldAccess(node.getParent());
+ if (!isAccessChainRoot) {
+ return;
+ }
+
+ Expression expression = node;
+ FieldAccessAdapter access = null;
+ while (FieldAccessAdapter.isFieldAccess(expression)) {
+ access = new FieldAccessAdapter(expression);
+ int nameIndex = access.getIdentifierIndex(this.tm);
+ // find a dot preceding the name, may not be there
+ for (int i = nameIndex - 1; i > this.tm.firstIndexIn(node, -1); i--) {
+ Token t = this.tm.get(i);
+ if (t.tokenType == TokenNameDOT) {
+ this.wrapIndexes.add(i);
+ this.secondaryWrapIndexes.add(nameIndex);
+ }
+ if (!t.isComment() && t.tokenType != TokenNamesuper) {
+ break;
+ }
+ }
+ expression = access.getExpression();
+ }
+ Collections.reverse(this.wrapIndexes);
+ this.wrapParentIndex = this.tm.lastIndexIn(expression != null ? expression : access.accessExpression, -1);
+ boolean isFollowedByInvocation = node.getParent() instanceof MethodInvocation
+ && node.getLocationInParent() == MethodInvocation.EXPRESSION_PROPERTY;
+ this.wrapGroupEnd = isFollowedByInvocation ? this.tm.lastIndexIn(node.getParent(), -1)
+ : new FieldAccessAdapter(node).getIdentifierIndex(this.tm);
+ // TODO need configuration for this, now only handles line breaks that cannot be
+ // removed
+ handleWrap(Alignment.M_NO_ALIGNMENT);
+ }
+
+ @Override
+ public boolean visit(InfixExpression node) {
+ Integer operatorPrecedence = OPERATOR_PRECEDENCE.get(node.getOperator());
+ if (operatorPrecedence == null) {
+ return true;
+ }
+ ASTNode parent = node.getParent();
+ if ((parent instanceof InfixExpression) && samePrecedence(node, (InfixExpression) parent)) {
+ return true; // this node has been handled higher in the AST
+ }
+
+ int wrappingOption = OPERATOR_WRAPPING_OPTION.get(node.getOperator()).applyAsInt(this.options);
+ boolean wrapBeforeOperator = OPERATOR_WRAP_BEFORE_OPTION.get(node.getOperator()).test(this.options);
+ if (this.tm.isStringConcatenation(node)) {
+ wrappingOption = this.options.alignment_for_string_concatenation;
+ wrapBeforeOperator = this.options.wrap_before_string_concatenation;
+ }
+
+ findTokensToWrap(node, wrapBeforeOperator, 0);
+ this.wrapParentIndex = this.wrapIndexes.remove(0);
+ this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+ if ((wrappingOption & Alignment.M_INDENT_ON_COLUMN) != 0 && this.wrapParentIndex > 0) {
+ this.wrapParentIndex--;
+ }
+ for (int i = this.wrapParentIndex; i >= 0; i--) {
+ if (!this.tm.get(i).isComment()) {
+ this.wrapParentIndex = i;
+ break;
+ }
+ }
+ handleWrap(wrappingOption, !wrapBeforeOperator, node);
+ return true;
+ }
+
+ private void findTokensToWrap(InfixExpression node, boolean wrapBeforeOperator, int depth) {
+ Expression left = node.getLeftOperand();
+ if (left instanceof InfixExpression && samePrecedence(node, (InfixExpression) left)) {
+ findTokensToWrap((InfixExpression) left, wrapBeforeOperator, depth + 1);
+ }
+ else if (this.wrapIndexes.isEmpty() // always add first operand, it will be taken
+ // as wrap parent
+ || !wrapBeforeOperator) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(left, -1));
+ }
+
+ Expression right = node.getRightOperand();
+ List extended = node.extendedOperands();
+ for (int i = -1; i < extended.size(); i++) {
+ Expression operand = (i == -1) ? right : extended.get(i);
+ if (operand instanceof InfixExpression && samePrecedence(node, (InfixExpression) operand)) {
+ findTokensToWrap((InfixExpression) operand, wrapBeforeOperator, depth + 1);
+ }
+ int indexBefore = this.tm.firstIndexBefore(operand, -1);
+ while (this.tm.get(indexBefore).isComment()) {
+ indexBefore--;
+ }
+ assert node.getOperator().toString().equals(this.tm.toString(indexBefore));
+ int indexAfter = this.tm.firstIndexIn(operand, -1);
+ this.wrapIndexes.add(wrapBeforeOperator ? indexBefore : indexAfter);
+ this.secondaryWrapIndexes.add(wrapBeforeOperator ? indexAfter : indexBefore);
+
+ if (!this.options.join_wrapped_lines) {
+ // TODO there should be an option for never joining wraps on opposite side
+ // of the operator
+ if (wrapBeforeOperator) {
+ if (this.tm.countLineBreaksBetween(this.tm.get(indexAfter - 1), this.tm.get(indexAfter)) > 0) {
+ this.wrapIndexes.add(indexAfter);
+ }
+ }
+ else {
+ if (this.tm.countLineBreaksBetween(this.tm.get(indexBefore), this.tm.get(indexBefore - 1)) > 0) {
+ this.wrapIndexes.add(indexBefore);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean samePrecedence(InfixExpression expression1, InfixExpression expression2) {
+ Integer precedence1 = OPERATOR_PRECEDENCE.get(expression1.getOperator());
+ Integer precedence2 = OPERATOR_PRECEDENCE.get(expression2.getOperator());
+ if (precedence1 == null || precedence2 == null) {
+ return false;
+ }
+ return precedence1.equals(precedence2);
+ }
+
+ @Override
+ public boolean visit(ConditionalExpression node) {
+ boolean chainsMatter = (this.options.alignment_for_conditional_expression_chain
+ & Alignment.SPLIT_MASK) != Alignment.M_NO_ALIGNMENT;
+ boolean isNextInChain = node.getParent() instanceof ConditionalExpression
+ && node == ((ConditionalExpression) node.getParent()).getElseExpression();
+ boolean isFirstInChain = node.getElseExpression() instanceof ConditionalExpression && !isNextInChain;
+ boolean wrapBefore = this.options.wrap_before_conditional_operator;
+ List before = wrapBefore ? this.wrapIndexes : this.secondaryWrapIndexes;
+ List after = wrapBefore ? this.secondaryWrapIndexes : this.wrapIndexes;
+ if (!chainsMatter || (!isFirstInChain && !isNextInChain)) {
+ before.add(this.tm.firstIndexAfter(node.getExpression(), TokenNameQUESTION));
+ before.add(this.tm.firstIndexAfter(node.getThenExpression(), TokenNameCOLON));
+ after.add(this.tm.firstIndexIn(node.getThenExpression(), -1));
+ after.add(this.tm.firstIndexIn(node.getElseExpression(), -1));
+ this.wrapParentIndex = this.tm.lastIndexIn(node.getExpression(), -1);
+ this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+ handleWrap(this.options.alignment_for_conditional_expression);
+
+ }
+ else if (isFirstInChain) {
+ List chain = new ArrayList<>();
+ chain.add(node);
+ ConditionalExpression next = node;
+ while (next.getElseExpression() instanceof ConditionalExpression) {
+ next = (ConditionalExpression) next.getElseExpression();
+ chain.add(next);
+ }
+
+ for (ConditionalExpression conditional : chain) {
+ before.add(this.tm.firstIndexAfter(conditional.getThenExpression(), TokenNameCOLON));
+ after.add(this.tm.firstIndexIn(conditional.getElseExpression(), -1));
+ }
+ this.wrapParentIndex = this.tm.firstIndexIn(node.getExpression(), -1);
+ this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+ handleWrap(this.options.alignment_for_conditional_expression_chain);
+
+ this.currentDepth++;
+ for (ConditionalExpression conditional : chain) {
+ before.add(this.tm.firstIndexAfter(conditional.getExpression(), TokenNameQUESTION));
+ after.add(this.tm.firstIndexIn(conditional.getThenExpression(), -1));
+ this.wrapParentIndex = this.tm.firstIndexIn(conditional.getExpression(), -1);
+ this.wrapGroupEnd = this.tm.lastIndexIn(conditional.getThenExpression(), -1);
+ handleWrap(this.options.alignment_for_conditional_expression);
+ }
+ this.currentDepth--;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(ArrayInitializer node) {
+ List expressions = node.expressions();
+ if (!expressions.isEmpty()) {
+ prepareElementsList(expressions, TokenNameCOMMA, TokenNameLBRACE);
+ handleWrap(this.options.alignment_for_expressions_in_array_initializer, node);
+ }
+ int openingBraceIndex = this.tm.firstIndexIn(node, TokenNameLBRACE);
+ Token openingBrace = this.tm.get(openingBraceIndex);
+ if (openingBrace.isNextLineOnWrap() && openingBrace.getWrapPolicy() == null && openingBraceIndex > 0) {
+ // add fake wrap policy to make sure the brace indentation is right
+ openingBrace.setWrapPolicy(new WrapPolicy(WrapMode.DISABLED, openingBraceIndex - 1, 0));
+ }
+ if (!this.options.join_wrapped_lines
+ && !this.options.insert_new_line_before_closing_brace_in_array_initializer) {
+ // if there is a line break before the closing brace, formatter should treat
+ // it as a valid wrap to preserve
+ int closingBraceIndex = this.tm.lastIndexIn(node, TokenNameRBRACE);
+ Token closingBrace = this.tm.get(closingBraceIndex);
+ if (this.tm.countLineBreaksBetween(this.tm.get(closingBraceIndex - 1), closingBrace) == 1) {
+ closingBrace.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, openingBraceIndex,
+ closingBraceIndex, 0, this.currentDepth, 1, true, false));
+ }
+ }
+ if (this.options.brace_position_for_array_initializer.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)
+ && openingBrace.getWrapPolicy() == null && (node.getParent() instanceof SingleMemberAnnotation
+ || node.getParent() instanceof MemberValuePair)) {
+ int parentIndex = this.tm.firstIndexIn(node.getParent(), -1);
+ int indent = this.options.indentation_size;
+ openingBrace.setWrapPolicy(new WrapPolicy(WrapMode.BLOCK_INDENT, parentIndex, indent));
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(Assignment node) {
+ int rightSideIndex = this.tm.firstIndexIn(node.getRightHandSide(), -1);
+ if (this.tm.get(rightSideIndex).getLineBreaksBefore() > 0) {
+ return true; // must be an array initializer in new line because of
+ // brace_position_for_array_initializer
+ }
+
+ int operatorIndex = this.tm.firstIndexBefore(node.getRightHandSide(), -1);
+ while (this.tm.get(operatorIndex).isComment()) {
+ operatorIndex--;
+ }
+ assert node.getOperator().toString().equals(this.tm.toString(operatorIndex));
+
+ this.wrapIndexes.add(this.options.wrap_before_assignment_operator ? operatorIndex : rightSideIndex);
+ this.secondaryWrapIndexes.add(this.options.wrap_before_assignment_operator ? rightSideIndex : operatorIndex);
+ this.wrapParentIndex = operatorIndex - 1;
+ this.wrapGroupEnd = this.tm.lastIndexIn(node.getRightHandSide(), -1);
+ handleWrap(this.options.alignment_for_assignment);
+ return true;
+ }
+
+ @Override
+ public boolean visit(VariableDeclarationFragment node) {
+ if (node.getInitializer() == null) {
+ return true;
+ }
+ int rightSideIndex = this.tm.firstIndexIn(node.getInitializer(), -1);
+ if (this.tm.get(rightSideIndex).getLineBreaksBefore() > 0) {
+ return true; // must be an array initializer in new line because of
+ // brace_position_for_array_initializer
+ }
+ int equalIndex = this.tm.firstIndexBefore(node.getInitializer(), TokenNameEQUAL);
+
+ this.wrapIndexes.add(this.options.wrap_before_assignment_operator ? equalIndex : rightSideIndex);
+ this.secondaryWrapIndexes.add(this.options.wrap_before_assignment_operator ? rightSideIndex : equalIndex);
+ this.wrapParentIndex = equalIndex - 1;
+ this.wrapGroupEnd = this.tm.lastIndexIn(node.getInitializer(), -1);
+ handleWrap(this.options.alignment_for_assignment);
+ return true;
+ }
+
+ @Override
+ public boolean visit(IfStatement node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_if_while_statement);
+
+ Statement elseStatement = node.getElseStatement();
+ boolean keepThenOnSameLine = this.options.keep_then_statement_on_same_line
+ || (this.options.keep_simple_if_on_one_line && elseStatement == null);
+ if (keepThenOnSameLine) {
+ handleSimpleLoop(node.getThenStatement(), this.options.alignment_for_compact_if);
+ }
+
+ if (this.options.keep_else_statement_on_same_line && elseStatement != null) {
+ handleSimpleLoop(elseStatement, this.options.alignment_for_compact_if);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(ForStatement node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_for_statement);
+
+ List initializers = node.initializers();
+ if (!initializers.isEmpty()) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(initializers.get(0), -1));
+ }
+ if (node.getExpression() != null) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(node.getExpression(), -1));
+ }
+ List updaters = node.updaters();
+ if (!updaters.isEmpty()) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(updaters.get(0), -1));
+ }
+ if (!this.wrapIndexes.isEmpty()) {
+ this.wrapParentIndex = lParen;
+ this.wrapGroupEnd = rParen;
+ handleWrap(this.options.alignment_for_expressions_in_for_loop_header);
+ }
+ if (this.options.keep_simple_for_body_on_same_line) {
+ handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(EnhancedForStatement node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_for_statement);
+
+ if (this.options.keep_simple_for_body_on_same_line) {
+ handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(WhileStatement node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_if_while_statement);
+
+ if (this.options.keep_simple_while_body_on_same_line) {
+ handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop);
+ }
+ return true;
+ }
+
+ private void handleSimpleLoop(Statement body, int wrappingOption) {
+ if (!(body instanceof Block)) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(body, -1));
+ this.wrapParentIndex = this.tm.firstIndexBefore(body, TokenNameRPAREN);
+ this.wrapGroupEnd = this.tm.lastIndexIn(body, -1);
+ handleWrap(wrappingOption, body.getParent());
+
+ body.accept(new ASTVisitor() {
+ @Override
+ public boolean visit(Block node) {
+ forceContinuousWrapping(node, WrapPreparator.this.tm.firstIndexIn(node, -1));
+ return false;
+ }
+ });
+ }
+ }
+
+ @Override
+ public void endVisit(DoStatement node) {
+ if (this.options.keep_simple_do_while_body_on_same_line && !(node.getBody() instanceof Block)) {
+ int whileIndex = this.tm.firstIndexAfter(node.getBody(), TokenNamewhile);
+ this.wrapIndexes.add(whileIndex);
+ this.wrapParentIndex = this.tm.lastIndexIn(node.getBody(), -1);
+ this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+
+ int alignment = this.options.alignment_for_compact_loop;
+ for (int i = this.tm.firstIndexIn(node, -1) + 1; i < whileIndex; i++) {
+ Token token = this.tm.get(i);
+ if (token.getLineBreaksBefore() > 0 || token.getLineBreaksAfter() > 0) {
+ alignment |= Alignment.M_FORCE;
+ }
+ }
+ handleWrap(alignment, node);
+ }
+ }
+
+ @Override
+ public boolean visit(TryStatement node) {
+ if (!node.resources().isEmpty()) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_try_clause);
+ }
+ prepareElementsList(node.resources(), TokenNameSEMICOLON, TokenNameLPAREN);
+ handleWrap(this.options.alignment_for_resources_in_try);
+ return true;
+ }
+
+ @Override
+ public boolean visit(UnionType node) {
+ List types = node.types();
+ if (types.isEmpty()) {
+ return true;
+ }
+ if (this.options.wrap_before_or_operator_multicatch) {
+ for (Type type : types) {
+ if (this.wrapIndexes.isEmpty()) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(type, -1));
+ }
+ else {
+ this.wrapIndexes.add(this.tm.firstIndexBefore(type, TokenNameOR));
+ this.secondaryWrapIndexes.add(this.tm.firstIndexIn(type, -1));
+ }
+ }
+ this.wrapParentIndex = this.tm.firstIndexBefore(node, -1);
+ while (this.tm.get(this.wrapParentIndex).isComment()) {
+ this.wrapParentIndex--;
+ }
+ this.wrapGroupEnd = this.tm.lastIndexIn(types.get(types.size() - 1), -1);
+ handleWrap(this.options.alignment_for_union_type_in_multicatch);
+ }
+ else {
+ prepareElementsList(types, TokenNameOR, TokenNameLPAREN);
+ handleWrap(this.options.alignment_for_union_type_in_multicatch);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(LambdaExpression node) {
+ int lParen = this.tm.firstIndexIn(node, -1);
+ if (this.tm.get(lParen).tokenType == TokenNameLPAREN) {
+ int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_lambda_declaration);
+ }
+ if (node.getBody() instanceof Block) {
+ forceContinuousWrapping(node.getBody(), this.tm.firstIndexIn(node, -1));
+
+ List statements = ((Block) node.getBody()).statements();
+ if (!statements.isEmpty()) {
+ int openBraceIndex = this.tm.firstIndexBefore(statements.get(0), TokenNameLBRACE);
+ int closeBraceIndex = this.tm.firstIndexAfter(statements.get(statements.size() - 1), TokenNameRBRACE);
+ boolean areKeptOnOneLine = this.tm.stream().skip(openBraceIndex + 1)
+ .limit(closeBraceIndex - openBraceIndex - 1)
+ .allMatch(t -> t.getLineBreaksBefore() == 0 && t.getLineBreaksAfter() == 0);
+ if (areKeptOnOneLine) {
+ for (Statement statement : statements) {
+ this.wrapIndexes.add(this.tm.firstIndexIn(statement, -1));
+ }
+ this.wrapParentIndex = openBraceIndex;
+ this.wrapGroupEnd = closeBraceIndex;
+ handleWrap(Alignment.M_ONE_PER_LINE_SPLIT, node);
+ this.tm.get(closeBraceIndex).setWrapPolicy(new WrapPolicy(WrapMode.TOP_PRIORITY, openBraceIndex,
+ closeBraceIndex, 0, this.currentDepth, 1, false, false));
+ }
+ }
+ }
+ if (node.hasParentheses()) {
+ List parameters = node.parameters();
+ // the legacy formatter didn't like wrapping lambda parameters, so neither do
+ // we
+ this.currentDepth++;
+ handleArguments(parameters, this.options.alignment_for_parameters_in_method_declaration);
+ this.currentDepth--;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(FieldDeclaration node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_field);
+ handleVariableDeclarations(node.fragments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(VariableDeclarationStatement node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_local_variable);
+ handleVariableDeclarations(node.fragments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(VariableDeclarationExpression node) {
+ handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_local_variable);
+ handleVariableDeclarations(node.fragments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(SingleVariableDeclaration node) {
+ handleAnnotations(node.modifiers(),
+ node.getParent() instanceof EnhancedForStatement
+ ? this.options.alignment_for_annotations_on_local_variable
+ : this.options.alignment_for_annotations_on_parameter);
+ return true;
+ }
+
+ @Override
+ public boolean visit(ParameterizedType node) {
+ prepareElementsList(node.typeArguments(), TokenNameCOMMA, TokenNameLESS);
+ handleWrap(this.options.alignment_for_parameterized_type_references);
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeMethodReference node) {
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(ExpressionMethodReference node) {
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(SuperMethodReference node) {
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ @Override
+ public boolean visit(CreationReference node) {
+ handleTypeArguments(node.typeArguments());
+ return true;
+ }
+
+ private void handleTypeArguments(List typeArguments) {
+ if (typeArguments.isEmpty()) {
+ return;
+ }
+ prepareElementsList(typeArguments, TokenNameCOMMA, TokenNameLESS);
+ handleWrap(this.options.alignment_for_type_arguments);
+ }
+
+ @Override
+ public boolean visit(ExportsDirective node) {
+ handleModuleStatement(node.modules(), TokenNameto);
+ return true;
+ }
+
+ @Override
+ public boolean visit(OpensDirective node) {
+ handleModuleStatement(node.modules(), TokenNameto);
+ return true;
+ }
+
+ @Override
+ public boolean visit(ProvidesDirective node) {
+ handleModuleStatement(node.implementations(), TokenNamewith);
+ return true;
+ }
+
+ private void handleModuleStatement(List names, int joiningTokenType) {
+ if (names.isEmpty()) {
+ return;
+ }
+ int joiningTokenIndex = this.tm.firstIndexBefore(names.get(0), joiningTokenType);
+ this.wrapParentIndex = this.tm.firstIndexBefore(names.get(0), TokenNameIdentifier);
+ this.wrapIndexes.add(joiningTokenIndex);
+ prepareElementsList(names, TokenNameCOMMA, -1);
+ handleWrap(this.options.alignment_for_module_statements, PREFERRED);
+ }
+
+ @Override
+ public boolean visit(CatchClause node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_catch_clause);
+ return true;
+ }
+
+ @Override
+ public boolean visit(SwitchStatement node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_switch_statement);
+ return true;
+ }
+
+ @Override
+ public boolean visit(SwitchExpression node) {
+ int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN);
+ int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_switch_statement);
+ return true;
+ }
+
+ @Override
+ public boolean visit(DoStatement node) {
+ int lParen = this.tm.firstIndexBefore(node.getExpression(), TokenNameLPAREN);
+ int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN);
+ handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_if_while_statement);
+ return true;
+ }
+
+ @Override
+ public boolean visit(AssertStatement node) {
+ Expression message = node.getMessage();
+ if (message != null) {
+ int atColon = this.tm.firstIndexBefore(message, TokenNameCOLON);
+ int afterColon = this.tm.firstIndexIn(message, -1);
+ if (this.options.wrap_before_assertion_message_operator) {
+ this.wrapIndexes.add(atColon);
+ this.secondaryWrapIndexes.add(afterColon);
+ }
+ else {
+ this.wrapIndexes.add(afterColon);
+ this.secondaryWrapIndexes.add(atColon);
+ }
+ this.wrapParentIndex = this.tm.firstIndexIn(node, -1);
+ this.wrapGroupEnd = this.tm.lastIndexIn(node, -1);
+ handleWrap(this.options.alignment_for_assertion_message);
+ }
+ return true;
+ }
+
+ /**
+ * Makes sure all new lines within given node will have wrap policy so that wrap
+ * executor will fix their indentation if necessary.
+ */
+ void forceContinuousWrapping(ASTNode node, int parentIndex) {
+ int parentIndent = this.tm.get(parentIndex).getIndent();
+ int indentChange = -parentIndent;
+ int lineStart = this.tm.findFirstTokenInLine(parentIndex);
+ for (int i = parentIndex; i >= lineStart; i--) {
+ int align = this.tm.get(i).getAlign();
+ if (align > 0) {
+ indentChange = -2 * parentIndent + align;
+ break;
+ }
+ }
+
+ Token previous = null;
+ int from = this.tm.firstIndexIn(node, -1);
+ int to = this.tm.lastIndexIn(node, -1);
+ for (int i = from; i <= to; i++) {
+ Token token = this.tm.get(i);
+ if ((token.getLineBreaksBefore() > 0 || (previous != null && previous.getLineBreaksAfter() > 0))
+ && (token.getWrapPolicy() == null || token.getWrapPolicy().wrapMode == WrapMode.BLOCK_INDENT)) {
+ int extraIndent = token.getIndent() + indentChange;
+ token.setWrapPolicy(new WrapPolicy(WrapMode.BLOCK_INDENT, parentIndex, extraIndent));
+ token.setIndent(parentIndent + extraIndent);
+ }
+ previous = token;
+ }
+ }
+
+ private void handleVariableDeclarations(List fragments) {
+ if (fragments.size() > 1) {
+ this.wrapParentIndex = this.tm.firstIndexIn(fragments.get(0), -1);
+ prepareElementsList(fragments, TokenNameCOMMA, -1);
+ this.wrapIndexes.remove(0);
+ handleWrap(this.options.alignment_for_multiple_fields);
+ }
+ }
+
+ private void handleArguments(List extends ASTNode> arguments, int wrappingOption) {
+ this.wrapPenalties.add(1 / PREFERRED);
+ prepareElementsList(arguments, TokenNameCOMMA, TokenNameLPAREN);
+ handleWrap(wrappingOption);
+ }
+
+ private void handleAnnotations(List extends IExtendedModifier> modifiers, int wrappingOption) {
+ Annotation last = null;
+ int i;
+ for (i = 0; i < modifiers.size(); i++) {
+ if (modifiers.get(i).isModifier()) {
+ break;
+ }
+ Annotation annotation = (Annotation) modifiers.get(i);
+ if (i == 0) {
+ this.wrapParentIndex = this.tm.firstIndexIn(annotation, -1);
+ }
+ else {
+ this.wrapIndexes.add(this.tm.firstIndexIn(annotation, -1));
+ this.wrapGroupEnd = this.tm.lastIndexIn(annotation, -1);
+ }
+ last = annotation;
+ }
+ handleWrap(wrappingOption, last);
+
+ if (i < modifiers.size()) {
+ // any annotations following other modifiers will be associated with
+ // declaration type
+ handleAnnotations(modifiers.subList(i + 1, modifiers.size()), this.options.alignment_for_type_annotations);
+ }
+ }
+
+ private void prepareElementsList(List extends ASTNode> elements, int separatorType, int wrapParentType) {
+ for (int i = 0; i < elements.size(); i++) {
+ ASTNode element = elements.get(i);
+ this.wrapIndexes.add(this.tm.firstIndexIn(element, -1));
+ if (i > 0) {
+ this.secondaryWrapIndexes.add(this.tm.firstIndexBefore(element, separatorType));
+ }
+ }
+ // wrapIndexes may have been filled with additional values even if arguments is
+ // empty
+ if (!this.wrapIndexes.isEmpty()) {
+ Token firstToken = this.tm.get(this.wrapIndexes.get(0));
+ if (this.wrapParentIndex < 0) {
+ this.wrapParentIndex = this.tm.findIndex(firstToken.originalStart - 1, wrapParentType, false);
+ }
+ if (!elements.isEmpty() && this.wrapGroupEnd < 0) {
+ this.wrapGroupEnd = this.tm.lastIndexIn(elements.get(elements.size() - 1), -1);
+ }
+ }
+ }
+
+ private void handleWrap(int wrappingOption) {
+ handleWrap(wrappingOption, null);
+ }
+
+ private void handleWrap(int wrappingOption, float firstPenaltyMultiplier) {
+ this.wrapPenalties.add(firstPenaltyMultiplier);
+ handleWrap(wrappingOption, null);
+ }
+
+ private void handleWrap(int wrappingOption, ASTNode parentNode) {
+ handleWrap(wrappingOption, true, parentNode);
+ }
+
+ private void handleWrap(int wrappingOption, boolean wrapPreceedingComments, ASTNode parentNode) {
+ doHandleWrap(wrappingOption, wrapPreceedingComments, parentNode);
+ this.wrapIndexes.clear();
+ this.secondaryWrapIndexes.clear();
+ this.wrapPenalties.clear();
+ this.wrapParentIndex = this.wrapGroupEnd = -1;
+ }
+
+ private void doHandleWrap(int wrappingOption, boolean wrapPreceedingComments, ASTNode parentNode) {
+ if (this.wrapIndexes.isEmpty()) {
+ return;
+ }
+ assert this.wrapParentIndex >= 0 && this.wrapParentIndex < this.wrapIndexes.get(0);
+ assert this.wrapGroupEnd >= this.wrapIndexes.get(this.wrapIndexes.size() - 1);
+
+ while (this.tm.get(this.wrapParentIndex).isComment() && this.wrapParentIndex > 0) {
+ this.wrapParentIndex--;
+ }
+
+ float penalty = this.wrapPenalties.isEmpty() ? 1 : this.wrapPenalties.get(0);
+ WrapPolicy policy = getWrapPolicy(wrappingOption, penalty, true, parentNode);
+
+ WrapPolicy existing = this.tm.get(this.wrapIndexes.get(0)).getWrapPolicy();
+ if (existing != null && existing.wrapMode == WrapMode.TOP_PRIORITY) {
+ // SEPARATE_LINES_IF_WRAPPED
+ assert existing.wrapParentIndex == this.wrapParentIndex;
+ this.wrapGroupEnd = existing.groupEndIndex;
+ policy = new WrapPolicy(WrapMode.TOP_PRIORITY, policy.wrapParentIndex, this.wrapGroupEnd,
+ policy.extraIndent, policy.structureDepth, policy.penaltyMultiplier, true, policy.indentOnColumn);
+ }
+
+ setTokenWrapPolicy(0, policy, true);
+
+ for (int i = 1; i < this.wrapIndexes.size(); i++) {
+ penalty = this.wrapPenalties.size() > i ? this.wrapPenalties.get(i) : 1;
+ if (penalty != policy.penaltyMultiplier || i == 1) {
+ policy = getWrapPolicy(wrappingOption, penalty, false, parentNode);
+ }
+ setTokenWrapPolicy(i, policy, wrapPreceedingComments);
+ }
+
+ if (!this.secondaryWrapIndexes.isEmpty()) {
+ int optionNoAlignment = (wrappingOption & ~Alignment.SPLIT_MASK) | Alignment.M_NO_ALIGNMENT;
+ policy = getWrapPolicy(optionNoAlignment, 1, false, parentNode);
+ for (int index : this.secondaryWrapIndexes) {
+ Token token = this.tm.get(index);
+ if (token.getWrapPolicy() == null) {
+ token.setWrapPolicy(policy);
+ }
+ }
+ }
+ }
+
+ private void setTokenWrapPolicy(int wrapIndexesIndex, WrapPolicy policy, boolean wrapPreceedingComments) {
+ int index = this.wrapIndexes.get(wrapIndexesIndex);
+ if (wrapPreceedingComments) {
+ for (int i = index - 1; i >= 0; i--) {
+ Token previous = this.tm.get(i);
+ if (!previous.isComment()) {
+ break;
+ }
+ if (previous.getWrapPolicy() == WrapPolicy.FORCE_FIRST_COLUMN) {
+ break;
+ }
+ if (previous.getLineBreaksAfter() == 0 && i == index - 1) {
+ index = i;
+ }
+ if (previous.getLineBreaksBefore() > 0) {
+ previous.setWrapPolicy(policy);
+ }
+ }
+ this.wrapIndexes.set(wrapIndexesIndex, index);
+ }
+
+ Token token = this.tm.get(index);
+ if (token.getWrapPolicy() == WrapPolicy.DISABLE_WRAP) {
+ return;
+ }
+
+ token.setWrapPolicy(policy);
+ if (policy.wrapMode == WrapMode.FORCE) {
+ token.breakBefore();
+ }
+ else if (this.options.join_wrapped_lines && token.tokenType == TokenNameCOMMENT_BLOCK) {
+ // allow wrap preparator to decide if this comment should be wrapped
+ token.clearLineBreaksBefore();
+ }
+ }
+
+ private WrapPolicy getWrapPolicy(int wrappingOption, float penaltyMultiplier, boolean isFirst, ASTNode parentNode) {
+ assert this.wrapParentIndex >= 0 && this.wrapGroupEnd >= 0;
+ int extraIndent = this.options.continuation_indentation;
+ boolean indentOnColumn = (wrappingOption & Alignment.M_INDENT_ON_COLUMN) != 0;
+ boolean isForceWrap = (wrappingOption & Alignment.M_FORCE) != 0;
+ boolean isAlreadyWrapped = false;
+ if (indentOnColumn) {
+ extraIndent = 0;
+ }
+ else if (parentNode instanceof Annotation) {
+ extraIndent = 0;
+ }
+ else if (parentNode instanceof EnumDeclaration) {
+ // special behavior for compatibility with legacy formatter
+ extraIndent = ((wrappingOption & Alignment.M_INDENT_BY_ONE) != 0) ? 2 : 1;
+ if (!this.options.indent_body_declarations_compare_to_enum_declaration_header) {
+ extraIndent--;
+ }
+ isAlreadyWrapped = isFirst;
+ }
+ else if (parentNode instanceof IfStatement || parentNode instanceof ForStatement
+ || parentNode instanceof EnhancedForStatement || parentNode instanceof WhileStatement) {
+ extraIndent = 1;
+ this.wrapParentIndex = this.tm.firstIndexIn(parentNode, -1); // only if
+ // !indoentOnColumn
+ }
+ else if (parentNode instanceof DoStatement) {
+ extraIndent = 0;
+ this.wrapParentIndex = this.tm.firstIndexIn(parentNode, -1); // only if
+ // !indoentOnColumn
+ }
+ else if (parentNode instanceof LambdaExpression) {
+ extraIndent = 1;
+ }
+ else if ((wrappingOption & Alignment.M_INDENT_BY_ONE) != 0) {
+ extraIndent = 1;
+ }
+ else if (parentNode instanceof ArrayInitializer) {
+ extraIndent = this.options.continuation_indentation_for_array_initializer;
+ isAlreadyWrapped = isFirst && this.options.insert_new_line_after_opening_brace_in_array_initializer;
+ }
+
+ WrapMode wrapMode = WrapMode.WHERE_NECESSARY;
+ boolean isTopPriority = false;
+ switch (wrappingOption & Alignment.SPLIT_MASK) {
+ case Alignment.M_NO_ALIGNMENT:
+ wrapMode = WrapMode.DISABLED;
+ isForceWrap = false;
+ break;
+ case Alignment.M_COMPACT_FIRST_BREAK_SPLIT:
+ isTopPriority = isFirst;
+ isForceWrap &= isFirst;
+ break;
+ case Alignment.M_ONE_PER_LINE_SPLIT:
+ isTopPriority = true;
+ break;
+ case Alignment.M_NEXT_SHIFTED_SPLIT:
+ isTopPriority = true;
+ if (!isFirst) {
+ extraIndent++;
+ }
+ break;
+ case Alignment.M_NEXT_PER_LINE_SPLIT:
+ isTopPriority = !isFirst;
+ isForceWrap &= !isFirst;
+ break;
+ }
+
+ if (isForceWrap) {
+ wrapMode = WrapMode.FORCE;
+ }
+ else if (isAlreadyWrapped) {
+ wrapMode = WrapMode.DISABLED; // to avoid triggering top priority wrapping
+ }
+ else if (isTopPriority) {
+ wrapMode = WrapMode.TOP_PRIORITY;
+ }
+ extraIndent *= this.options.indentation_size;
+ return new WrapPolicy(wrapMode, this.wrapParentIndex, this.wrapGroupEnd, extraIndent, this.currentDepth,
+ penaltyMultiplier, isFirst, indentOnColumn);
+ }
+
+ public void finishUp(ASTNode astRoot, List regions) {
+ preserveExistingLineBreaks();
+ applyBreaksOutsideRegions(regions);
+ new WrapExecutor(this.tm, this.options, regions).executeWraps();
+ this.aligner.alignComments();
+ wrapComments();
+ fixEnumConstantIndents(astRoot);
+ }
+
+ private void preserveExistingLineBreaks() {
+ // normally n empty lines = n+1 line breaks, but not at the file start and end
+ Token first = this.tm.get(0);
+ int startingBreaks = first.getLineBreaksBefore();
+ first.clearLineBreaksBefore();
+ first.putLineBreaksBefore(startingBreaks - 1);
+
+ this.tm.traverse(0, new TokenTraverser() {
+ boolean join_wrapped_lines = WrapPreparator.this.options.join_wrapped_lines;
+
+ @Override
+ protected boolean token(Token token, int index) {
+ int lineBreaks = getLineBreaksToPreserve(getPrevious(), token);
+ if (lineBreaks > 1 || (!this.join_wrapped_lines && token.isWrappable()) || index == 0) {
+ token.putLineBreaksBefore(lineBreaks);
+ }
+ return true;
+ }
+
+ });
+
+ Token last = this.tm.get(this.tm.size() - 1);
+ last.clearLineBreaksAfter();
+ int endingBreaks = getLineBreaksToPreserve(last, null);
+ if (endingBreaks > 0) {
+ last.putLineBreaksAfter(endingBreaks);
+ }
+ else if ((this.kind & (CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.K_MODULE_INFO)) != 0
+ && this.options.insert_new_line_at_end_of_file_if_missing) {
+ last.breakAfter();
+ }
+ }
+
+ int getLineBreaksToPreserve(Token token1, Token token2) {
+ if ((token1 != null && !token1.isPreserveLineBreaksAfter())
+ || (token2 != null && !token2.isPreserveLineBreaksBefore())) {
+ return 0;
+ }
+ if (token1 != null) {
+ List structure = token1.getInternalStructure();
+ if (structure != null && !structure.isEmpty()) {
+ token1 = structure.get(structure.size() - 1);
+ }
+ }
+ if (token2 != null) {
+ List structure = token2.getInternalStructure();
+ if (structure != null && !structure.isEmpty()) {
+ token2 = structure.get(0);
+ }
+ }
+ int lineBreaks = WrapPreparator.this.tm.countLineBreaksBetween(token1, token2);
+ int toPreserve = this.options.number_of_empty_lines_to_preserve;
+ if (token1 != null && token2 != null) {
+ toPreserve++; // n empty lines = n+1 line breaks, except for file start and
+ // end
+ }
+ return Math.min(lineBreaks, toPreserve);
+ }
+
+ private void applyBreaksOutsideRegions(List regions) {
+ String source = this.tm.getSource();
+ int previousRegionEnd = 0;
+ for (IRegion region : regions) {
+ int index = this.tm.findIndex(previousRegionEnd, -1, true);
+ Token token = this.tm.get(index);
+ if (this.tm.countLineBreaksBetween(source, previousRegionEnd,
+ Math.min(token.originalStart, region.getOffset())) > 0) {
+ token.breakBefore();
+ }
+ for (index++; index < this.tm.size(); index++) {
+ Token next = this.tm.get(index);
+ if (next.originalStart > region.getOffset()) {
+ if (this.tm.countLineBreaksBetween(source, token.originalEnd, region.getOffset()) > 0) {
+ next.breakBefore();
+ }
+ break;
+ }
+ if (this.tm.countLineBreaksBetween(token, next) > 0) {
+ next.breakBefore();
+ }
+ token = next;
+ }
+ previousRegionEnd = region.getOffset() + region.getLength() - 1;
+ }
+ }
+
+ private void wrapComments() {
+ CommentWrapExecutor commentWrapper = new CommentWrapExecutor(this.tm, this.options);
+ boolean isNLSTagInLine = false;
+ for (int i = 0; i < this.tm.size(); i++) {
+ Token token = this.tm.get(i);
+ if (token.getLineBreaksBefore() > 0 || token.getLineBreaksAfter() > 0) {
+ isNLSTagInLine = false;
+ }
+ if (token.hasNLSTag()) {
+ assert token.tokenType == TokenNameStringLiteral;
+ isNLSTagInLine = true;
+ }
+ List structure = token.getInternalStructure();
+ if (token.isComment() && structure != null && !structure.isEmpty() && !isNLSTagInLine) {
+ int startPosition = this.tm.getPositionInLine(i);
+ if (token.tokenType == TokenNameCOMMENT_LINE) {
+ commentWrapper.wrapLineComment(token, startPosition);
+ }
+ else {
+ assert token.tokenType == TokenNameCOMMENT_BLOCK || token.tokenType == TokenNameCOMMENT_JAVADOC;
+ commentWrapper.wrapMultiLineComment(token, startPosition, false, false);
+ }
+ }
+ }
+ }
+
+ private void fixEnumConstantIndents(ASTNode astRoot) {
+ if (this.options.use_tabs_only_for_leading_indentations) {
+ // enum constants should be indented like other declarations, not like wrapped
+ // elements
+ astRoot.accept(new ASTVisitor() {
+
+ @Override
+ public boolean visit(EnumConstantDeclaration node) {
+ WrapPreparator.this.tm.firstTokenIn(node, -1).setWrapPolicy(null);
+ return true;
+ }
+ });
+ }
+ }
+
+ private void handleParenthesesPositions(int openingParenIndex, int closingParenIndex, String positionsSetting) {
+ boolean isEmpty = openingParenIndex + 1 == closingParenIndex;
+ switch (positionsSetting) {
+ case DefaultCodeFormatterConstants.COMMON_LINES:
+ // nothing to do
+ break;
+ case DefaultCodeFormatterConstants.SEPARATE_LINES_IF_WRAPPED:
+ if (isEmpty) {
+ break;
+ }
+ this.tm.get(openingParenIndex + 1).setWrapPolicy(new WrapPolicy(WrapMode.TOP_PRIORITY, openingParenIndex,
+ closingParenIndex, this.options.indentation_size, this.currentDepth, 1, true, false));
+ this.tm.get(closingParenIndex).setWrapPolicy(new WrapPolicy(WrapMode.TOP_PRIORITY, openingParenIndex,
+ closingParenIndex, 0, this.currentDepth, 1, false, false));
+ break;
+ case DefaultCodeFormatterConstants.SEPARATE_LINES_IF_NOT_EMPTY:
+ if (isEmpty) {
+ break;
+ }
+ //$FALL-THROUGH$
+ case DefaultCodeFormatterConstants.SEPARATE_LINES:
+ case DefaultCodeFormatterConstants.PRESERVE_POSITIONS:
+ boolean always = !positionsSetting.equals(DefaultCodeFormatterConstants.PRESERVE_POSITIONS);
+ Token afterOpening = this.tm.get(openingParenIndex + 1);
+ if (always || this.tm.countLineBreaksBetween(this.tm.get(openingParenIndex), afterOpening) > 0) {
+ afterOpening.setWrapPolicy(
+ new WrapPolicy(WrapMode.WHERE_NECESSARY, openingParenIndex, this.options.indentation_size));
+ afterOpening.breakBefore();
+ }
+ Token closingParen = this.tm.get(closingParenIndex);
+ if (always || this.tm.countLineBreaksBetween(this.tm.get(closingParenIndex - 1), closingParen) > 0) {
+ closingParen.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, openingParenIndex, 0));
+ closingParen.breakBefore();
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unrecognized parentheses positions setting: " + positionsSetting); //$NON-NLS-1$
+ }
+ }
+
+ // @formatter:on
+
+}
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml
index b58b2ad3..9be11ea0 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.21-SNAPSHOT
+ 0.0.48-SNAPSHOT
spring-javaformat-formatter-eclipse-rewriter
Spring JavaFormat Eclipse Rewriter
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java
index 9086d63f..7053dc0c 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
@@ -29,6 +29,7 @@
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
+import java.util.function.Function;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
@@ -63,38 +64,59 @@ public final class EclipseRewriter {
private EclipseRewriter() {
}
- public void rewrite(String file) throws IOException {
+ public void rewrite(JdkVersion jdkVersion, String file) throws IOException {
System.out.println("Rewriting classes in " + file);
URI uri = URI.create("jar:file:" + Paths.get(file).toUri().getPath());
try (FileSystem zip = FileSystems.newFileSystem(uri, Collections.singletonMap("create", "true"))) {
- rewrite(zip);
+ rewrite(jdkVersion, zip);
}
}
- private void rewrite(FileSystem zip) throws IOException {
- Path path = zip.getPath("org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.class");
- ClassWriter writer = new ClassWriter(0);
+ private void rewrite(JdkVersion jdkVersion, FileSystem zip) throws IOException {
+ rewrite(zip, "org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.class",
+ DefaultCodeFormatterManipulator::new);
+ if (jdkVersion == JdkVersion.V8) {
+ rewrite(zip, "org/eclipse/osgi/util/NLS$1.class", NlsJdk8Manipulator::new);
+ deleteWrapPreparator(zip);
+ }
+ else {
+ rewrite(zip, "org/eclipse/osgi/util/NLS.class", NlsJdk17Manipulator::new);
+ }
+ }
+
+ private void rewrite(FileSystem zip, String name, Function manipulator)
+ throws IOException {
+ ClassWriter classWriter = new ClassWriter(0);
+ Path path = zip.getPath(name);
try (InputStream in = Files.newInputStream(path)) {
- DefaultCodeFormatterManipulator manipulator = new DefaultCodeFormatterManipulator(writer);
ClassReader reader = new ClassReader(in);
- reader.accept(manipulator, 0);
+ reader.accept(manipulator.apply(classWriter), 0);
}
- Files.copy(new ByteArrayInputStream(writer.toByteArray()), path, StandardCopyOption.REPLACE_EXISTING);
+ Files.copy(new ByteArrayInputStream(classWriter.toByteArray()), path, StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ private void deleteWrapPreparator(FileSystem zip) throws IOException {
+ Path path = zip.getPath("org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.class");
+ Files.delete(path);
}
public static void main(String[] args) throws Exception {
- new EclipseRewriter().rewrite(args[0]);
+ new EclipseRewriter().rewrite(JdkVersion.valueOf("V" + args[0]), args[1]);
}
+ /**
+ * {@link ClassVisitor} to make some fields and methods from
+ * {@code DefaultCodeFormatter} public.
+ */
private static class DefaultCodeFormatterManipulator extends ClassVisitor {
DefaultCodeFormatterManipulator(ClassVisitor visitor) {
- super(Opcodes.ASM5, visitor);
+ super(Opcodes.ASM9, visitor);
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
- if (access == Opcodes.ACC_PRIVATE && UPDATED_FIELDS.contains(name)) {
+ if ((access & Opcodes.ACC_PRIVATE) != 0 && UPDATED_FIELDS.contains(name)) {
access = Opcodes.ACC_PROTECTED;
}
return super.visitField(access, name, desc, signature, value);
@@ -102,7 +124,7 @@ public FieldVisitor visitField(int access, String name, String desc, String sign
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- if (access == Opcodes.ACC_PRIVATE && UPDATED_METHODS.contains(name)) {
+ if ((access & Opcodes.ACC_PRIVATE) != 0 && UPDATED_METHODS.contains(name)) {
access = Opcodes.ACC_PROTECTED;
}
return new DefaultCodeFormatterMethodManipulator(
@@ -111,10 +133,14 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
}
+ /**
+ * {@link MethodVisitor} to make some fields and methods from
+ * {@code DefaultCodeFormatter} public.
+ */
private static class DefaultCodeFormatterMethodManipulator extends MethodVisitor {
DefaultCodeFormatterMethodManipulator(MethodVisitor mv) {
- super(Opcodes.ASM5, mv);
+ super(Opcodes.ASM9, mv);
}
@Override
@@ -127,4 +153,109 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc,
}
+ /**
+ * {@link ClassVisitor} to update the {@code NLS} class in the JDK 8 version so it
+ * doesn't use a System property to disable warning messages.
+ */
+ private static class NlsJdk8Manipulator extends ClassVisitor {
+
+ NlsJdk8Manipulator(ClassVisitor visitor) {
+ super(Opcodes.ASM9, visitor);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ if ("run".equals(name) && desc.contains("Boolean")) {
+ return new NslJdk8MethodManipulator(super.visitMethod(access, name, desc, signature, exceptions));
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ }
+
+ /**
+ * {@link MethodVisitor} to update the {@code NLS} class in the JDK 8 version so it
+ * doesn't use a System property to disable warning messages.
+ */
+ private static class NslJdk8MethodManipulator extends MethodVisitor {
+
+ private final MethodVisitor methodVisitor;
+
+ NslJdk8MethodManipulator(MethodVisitor mv) {
+ super(Opcodes.ASM9, null);
+ this.methodVisitor = mv;
+ }
+
+ @Override
+ public void visitEnd() {
+ MethodVisitor mv = this.methodVisitor;
+ mv.visitCode();
+ mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ }
+
+ /**
+ * {@link ClassVisitor} to update the {@code NLS} class in the JDK 8 version so it
+ * doesn't use a System property to disable warning messages.
+ */
+ private static class NlsJdk17Manipulator extends ClassVisitor {
+
+ NlsJdk17Manipulator(ClassVisitor visitor) {
+ super(Opcodes.ASM9, visitor);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ if ("".equals(name)) {
+ return new NslJdk17MethodManipulator(super.visitMethod(access, name, desc, signature, exceptions));
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ }
+
+ /**
+ * {@link MethodVisitor} to update the {@code NLS} class in the JDK 8 version so it
+ * doesn't use a System property to disable warning messages.
+ */
+ private static class NslJdk17MethodManipulator extends MethodVisitor {
+
+ private final MethodVisitor methodVisitor;
+
+ NslJdk17MethodManipulator(MethodVisitor mv) {
+ super(Opcodes.ASM9, null);
+ this.methodVisitor = mv;
+ }
+
+ @Override
+ public void visitEnd() {
+ MethodVisitor mv = this.methodVisitor;
+ mv.visitCode();
+ mv.visitInsn(Opcodes.ICONST_0);
+ mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
+ mv.visitFieldInsn(Opcodes.PUTSTATIC, "org/eclipse/osgi/util/NLS", "EMPTY_ARGS", "[Ljava/lang/Object;");
+ mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
+ mv.visitFieldInsn(Opcodes.PUTSTATIC, "org/eclipse/osgi/util/NLS", "ignoreWarnings", "Z");
+ mv.visitTypeInsn(Opcodes.NEW, "java/lang/Object");
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false);
+ mv.visitFieldInsn(Opcodes.PUTSTATIC, "org/eclipse/osgi/util/NLS", "ASSIGNED", "Ljava/lang/Object;");
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(2, 0);
+ mv.visitEnd();
+ }
+
+ }
+
+ enum JdkVersion {
+
+ V8, V11
+
+ }
+
}
diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml
index b895cc7e..dab30621 100644
--- a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml
+++ b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml
@@ -6,185 +6,79 @@
io.spring.javaformat
spring-javaformat
- 0.0.21-SNAPSHOT
+ 0.0.48-SNAPSHOT
spring-javaformat-formatter-eclipse-runtime
- eclipse-plugin
Spring JavaFormat Eclipse Runtime
${basedir}/../..
- org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source
-
-
- Eclipse Public License, Version 1.0
- https://www.eclipse.org/legal/epl-v10.html
-
-
+
+
+ io.spring.javaformat
+ spring-javaformat-formatter-eclipse-jdk8
+ ${project.version}
+ true
+
+
org.apache.maven.plugins
- maven-antrun-plugin
-
-
- io.spring.javaformat
- spring-javaformat-formatter-eclipse-rewriter
- ${project.version}
-
-
- ant-contrib
- ant-contrib
- ${ant-contrib.version}
-
-
- ant
- ant
-
-
-
-
- org.apache.ant
- ant-nodeps
- ${ant.version}
-
-
+ maven-jar-plugin
- rewrite-bytecode
- package
-
- run
-
-
-
-
-
-
-
-
-
-
- repackage-source
+ empty-javadoc-jar
package
- run
+ jar
-
-
-
-
+ javadoc
-
- org.eclipse.tycho
- tycho-packaging-plugin
-
- false
-
-
-
- org.eclipse.tycho
- tycho-maven-plugin
-
-
- org.eclipse.tycho
- target-platform-configuration
-
-
- org.eclipse.tycho
- tycho-versions-plugin
-
-
- update-eclipse-version
- initialize
-
- update-eclipse-metadata
-
-
-
-
org.apache.maven.plugins
- maven-dependency-plugin
+ maven-source-plugin
- unpack-dependencies
-
- unpack-dependencies
-
- prepare-package
-
- ${project.build.outputDirectory}
- META-INF/*,**.dll,**.so,**.java
- ${sourceartifacts}
-
-
-
- unpack-source-dependencies
+ attach-source
+ package
- unpack-dependencies
+ jar
- prepare-package
-
- ${project.build.directory}/sources
- ${sourceartifacts}
-
- com.github.wvengen
- proguard-maven-plugin
+ org.apache.maven.plugins
+ maven-shade-plugin
- reduce-eclipse-runtime
package
- proguard
+ shade
- false
-
- ${java.home}/lib/rt.jar
- ${java.home}/lib/jsse.jar
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk8
+
+ org/eclipse/jdt/**
+ META-INF/ECLIPSE_.SF
+ META-INF/ECLIPSE_.RSA
+
+
+
+ false
+ true
+ true
-
-
- io.spring.javaformat
- spring-javaformat-formatter-eclipse-rewriter
- ${project.version}
- provided
-
-