@@ -63,8 +63,9 @@ public static int version() {
6363 public static class Support <V > {
6464 private final String fmtName ;
6565 private final Comparator <? super V > fmtVersionComparator ;
66- private final NavigableMap <Integer , V > jvm2fmtVersion ;
67- private final NavigableMap <V , Integer > fmt2jvmVersion ;
66+ private final NavigableMap <Integer , V > jvm2fmtMaxVersion ;
67+ private final NavigableMap <Integer , V > jvm2fmtMinVersion ;
68+ private final NavigableMap <V , Integer > fmtMaxVersion2jvmVersion ;
6869
6970 private Support (String fromatterName ) {
7071 this (fromatterName , new SemanticVersionComparator <V >());
@@ -73,40 +74,60 @@ private Support(String fromatterName) {
7374 private Support (String formatterName , Comparator <? super V > formatterVersionComparator ) {
7475 fmtName = formatterName ;
7576 fmtVersionComparator = formatterVersionComparator ;
76- jvm2fmtVersion = new TreeMap <Integer , V >();
77- fmt2jvmVersion = new TreeMap <V , Integer >(formatterVersionComparator );
77+ jvm2fmtMaxVersion = new TreeMap <>();
78+ jvm2fmtMinVersion = new TreeMap <>();
79+ fmtMaxVersion2jvmVersion = new TreeMap <>(formatterVersionComparator );
7880 }
7981
8082 /**
81- * Add supported formatter version
83+ * Add maximum supported formatter version
8284 * @param minimumJvmVersion Minimum Java version required
8385 * @param maxFormatterVersion Maximum formatter version supported by the Java version
8486 * @return this
8587 */
8688 public Support <V > add (int minimumJvmVersion , V maxFormatterVersion ) {
8789 Objects .requireNonNull (maxFormatterVersion );
88- if (null != jvm2fmtVersion .put (minimumJvmVersion , maxFormatterVersion )) {
90+ if (null != jvm2fmtMaxVersion .put (minimumJvmVersion , maxFormatterVersion )) {
8991 throw new IllegalArgumentException (String .format ("Added duplicate entry for JVM %d+." , minimumJvmVersion ));
9092 }
91- if (null != fmt2jvmVersion .put (maxFormatterVersion , minimumJvmVersion )) {
93+ if (null != fmtMaxVersion2jvmVersion .put (maxFormatterVersion , minimumJvmVersion )) {
9294 throw new IllegalArgumentException (String .format ("Added duplicate entry for formatter version %s." , maxFormatterVersion ));
9395 }
96+ verifyVersionRangesDoNotIntersect (jvm2fmtMaxVersion , minimumJvmVersion , maxFormatterVersion );
97+ return this ;
98+ }
99+
100+ public Support <V > addMin (int minimumJvmVersion , V minFormatterVersion ) {
101+ Objects .requireNonNull (minFormatterVersion );
102+ if (null != jvm2fmtMinVersion .put (minimumJvmVersion , minFormatterVersion )) {
103+ throw new IllegalArgumentException (String .format ("Added duplicate entry for JVM %d+." , minimumJvmVersion ));
104+ }
105+ verifyVersionRangesDoNotIntersect (jvm2fmtMinVersion , minimumJvmVersion , minFormatterVersion );
106+ return this ;
107+ }
108+
109+ private void verifyVersionRangesDoNotIntersect (NavigableMap <Integer , V > jvm2fmtVersion , int minimumJvmVersion , V formatterVersion ) {
94110 Map .Entry <Integer , V > lower = jvm2fmtVersion .lowerEntry (minimumJvmVersion );
95- if ((null != lower ) && (fmtVersionComparator .compare (maxFormatterVersion , lower .getValue ()) <= 0 )) {
96- throw new IllegalArgumentException (String .format ("%d/%s should be lower than %d/%s" , minimumJvmVersion , maxFormatterVersion , lower .getKey (), lower .getValue ()));
111+ if ((null != lower ) && (fmtVersionComparator .compare (formatterVersion , lower .getValue ()) <= 0 )) {
112+ throw new IllegalArgumentException (String .format ("%d/%s should be lower than %d/%s" , minimumJvmVersion , formatterVersion , lower .getKey (), lower .getValue ()));
97113 }
98114 Map .Entry <Integer , V > higher = jvm2fmtVersion .higherEntry (minimumJvmVersion );
99- if ((null != higher ) && (fmtVersionComparator .compare (maxFormatterVersion , higher .getValue ()) >= 0 )) {
100- throw new IllegalArgumentException (String .format ("%d/%s should be higher than %d/%s" , minimumJvmVersion , maxFormatterVersion , higher .getKey (), higher .getValue ()));
115+ if ((null != higher ) && (fmtVersionComparator .compare (formatterVersion , higher .getValue ()) >= 0 )) {
116+ throw new IllegalArgumentException (String .format ("%d/%s should be higher than %d/%s" , minimumJvmVersion , formatterVersion , higher .getKey (), higher .getValue ()));
101117 }
102- return this ;
103118 }
104119
105120 /** @return Highest formatter version recommended for this JVM (null, if JVM not supported) */
106121 @ Nullable
107122 public V getRecommendedFormatterVersion () {
108- Integer configuredJvmVersionOrNull = jvm2fmtVersion .floorKey (Jvm .version ());
109- return (null == configuredJvmVersionOrNull ) ? null : jvm2fmtVersion .get (configuredJvmVersionOrNull );
123+ Integer configuredJvmVersionOrNull = jvm2fmtMaxVersion .floorKey (Jvm .version ());
124+ return (null == configuredJvmVersionOrNull ) ? null : jvm2fmtMaxVersion .get (configuredJvmVersionOrNull );
125+ }
126+
127+ @ Nullable
128+ public V getMinimumRequiredFormatterVersion () {
129+ Integer configuredJvmVersionOrNull = jvm2fmtMinVersion .floorKey (Jvm .version ());
130+ return (null == configuredJvmVersionOrNull ) ? null : jvm2fmtMinVersion .get (configuredJvmVersionOrNull );
110131 }
111132
112133 /**
@@ -123,10 +144,17 @@ public void assertFormatterSupported(V formatterVersion) {
123144 }
124145
125146 private String buildUnsupportedFormatterMessage (V fmtVersion ) {
147+ // check if the jvm version is to low for the formatter version
126148 int requiredJvmVersion = getRequiredJvmVersion (fmtVersion );
127149 if (Jvm .version () < requiredJvmVersion ) {
128150 return buildUpgradeJvmMessage (fmtVersion ) + "Upgrade your JVM or try " + toString ();
129151 }
152+ // check if the formatter version is too low for the jvm version
153+ V minimumFormatterVersion = getMinimumRequiredFormatterVersion ();
154+ if ((null != minimumFormatterVersion ) && (fmtVersionComparator .compare (fmtVersion , minimumFormatterVersion ) < 0 )) {
155+ return String .format ("You are running Spotless on JVM %d, which requires %s of at least %s (you are using %s).%n" , Jvm .version (), fmtName , minimumFormatterVersion , fmtVersion );
156+ }
157+ // otherwise all is well
130158 return "" ;
131159 }
132160
@@ -137,7 +165,7 @@ private String buildUpgradeJvmMessage(V fmtVersion) {
137165 if (null != recommendedFmtVersionOrNull ) {
138166 builder .append (String .format (", which limits you to %s %s.%n" , fmtName , recommendedFmtVersionOrNull ));
139167 } else {
140- Entry <V , Integer > nextFmtVersionOrNull = fmt2jvmVersion .ceilingEntry (fmtVersion );
168+ Entry <V , Integer > nextFmtVersionOrNull = fmtMaxVersion2jvmVersion .ceilingEntry (fmtVersion );
141169 if (null != nextFmtVersionOrNull ) {
142170 builder .append (String .format (". %s %s requires JVM %d+" , fmtName , fmtVersion , nextFmtVersionOrNull .getValue ()));
143171 }
@@ -147,12 +175,12 @@ private String buildUpgradeJvmMessage(V fmtVersion) {
147175 }
148176
149177 private int getRequiredJvmVersion (V fmtVersion ) {
150- Entry <V , Integer > entry = fmt2jvmVersion .ceilingEntry (fmtVersion );
178+ Entry <V , Integer > entry = fmtMaxVersion2jvmVersion .ceilingEntry (fmtVersion );
151179 if (null == entry ) {
152- entry = fmt2jvmVersion .lastEntry ();
180+ entry = fmtMaxVersion2jvmVersion .lastEntry ();
153181 }
154182 if (null != entry ) {
155- V maxKnownFmtVersion = jvm2fmtVersion .get (entry .getValue ());
183+ V maxKnownFmtVersion = jvm2fmtMaxVersion .get (entry .getValue ());
156184 if (fmtVersionComparator .compare (fmtVersion , maxKnownFmtVersion ) <= 0 ) {
157185 return entry .getValue ();
158186 }
@@ -170,15 +198,15 @@ public FormatterFunc suggestLaterVersionOnError(V formatterVersion, FormatterFun
170198 Objects .requireNonNull (formatterVersion );
171199 Objects .requireNonNull (originalFunc );
172200 final String hintUnsupportedProblem = buildUnsupportedFormatterMessage (formatterVersion );
173- final String proposeDiffererntFormatter = hintUnsupportedProblem .isEmpty () ? buildUpgradeFormatterMessage (formatterVersion ) : hintUnsupportedProblem ;
174- return proposeDiffererntFormatter .isEmpty () ? originalFunc : new FormatterFunc () {
201+ final String proposeDifferentFormatter = hintUnsupportedProblem .isEmpty () ? buildUpgradeFormatterMessage (formatterVersion ) : hintUnsupportedProblem ;
202+ return proposeDifferentFormatter .isEmpty () ? originalFunc : new FormatterFunc () {
175203
176204 @ Override
177205 public String apply (String unix , File file ) throws Exception {
178206 try {
179207 return originalFunc .apply (unix , file );
180208 } catch (Exception e ) {
181- throw new Exception (proposeDiffererntFormatter , e );
209+ throw new Exception (proposeDifferentFormatter , e );
182210 }
183211 }
184212
@@ -187,7 +215,7 @@ public String apply(String input) throws Exception {
187215 try {
188216 return originalFunc .apply (input );
189217 } catch (Exception e ) {
190- throw new Exception (proposeDiffererntFormatter , e );
218+ throw new Exception (proposeDifferentFormatter , e );
191219 }
192220 }
193221
@@ -196,16 +224,25 @@ public String apply(String input) throws Exception {
196224
197225 private String buildUpgradeFormatterMessage (V fmtVersion ) {
198226 StringBuilder builder = new StringBuilder ();
227+ // check if the formatter is not supported on this jvm
228+ V minimumFormatterVersion = getMinimumRequiredFormatterVersion ();
199229 V recommendedFmtVersionOrNull = getRecommendedFormatterVersion ();
200- if (null != recommendedFmtVersionOrNull && (fmtVersionComparator .compare (fmtVersion , recommendedFmtVersionOrNull ) < 0 )) {
230+ if ((null != minimumFormatterVersion ) && (fmtVersionComparator .compare (fmtVersion , minimumFormatterVersion ) < 0 )) {
231+ builder .append (String .format ("You are running Spotless on JVM %d, which requires %s of at least %s.%n" , Jvm .version (), fmtName , minimumFormatterVersion ));
232+ builder .append (String .format ("You are using %s %s.%n" , fmtName , fmtVersion ));
233+ if (null != recommendedFmtVersionOrNull ) {
234+ builder .append (String .format ("%s %s is the recommended version, which may have fixed this problem.%n" , fmtName , recommendedFmtVersionOrNull ));
235+ }
236+ // check if the formatter is outdated on this jvm
237+ } else if (null != recommendedFmtVersionOrNull && (fmtVersionComparator .compare (fmtVersion , recommendedFmtVersionOrNull ) < 0 )) {
201238 builder .append (String .format ("%s %s is currently being used, but outdated.%n" , fmtName , fmtVersion ));
202239 builder .append (String .format ("%s %s is the recommended version, which may have fixed this problem.%n" , fmtName , recommendedFmtVersionOrNull ));
203240 builder .append (String .format ("%s %s requires JVM %d+." , fmtName , recommendedFmtVersionOrNull , getRequiredJvmVersion (recommendedFmtVersionOrNull )));
204241 } else {
205- V higherFormatterVersionOrNull = fmt2jvmVersion .higherKey (fmtVersion );
242+ V higherFormatterVersionOrNull = fmtMaxVersion2jvmVersion .higherKey (fmtVersion );
206243 if (null != higherFormatterVersionOrNull ) {
207244 builder .append (buildUpgradeJvmMessage (fmtVersion ));
208- Integer higherJvmVersion = fmt2jvmVersion .get (higherFormatterVersionOrNull );
245+ Integer higherJvmVersion = fmtMaxVersion2jvmVersion .get (higherFormatterVersionOrNull );
209246 builder .append (String .format ("If you upgrade your JVM to %d+, then you can use %s %s, which may have fixed this problem." , higherJvmVersion , fmtName , higherFormatterVersionOrNull ));
210247 }
211248 }
@@ -215,7 +252,7 @@ private String buildUpgradeFormatterMessage(V fmtVersion) {
215252 @ Override
216253 public String toString () {
217254 return String .format ("%s alternatives:%n" , fmtName ) +
218- jvm2fmtVersion .entrySet ().stream ().map (
255+ jvm2fmtMaxVersion .entrySet ().stream ().map (
219256 e -> String .format ("- Version %s requires JVM %d+" , e .getValue (), e .getKey ())).collect (Collectors .joining (System .lineSeparator ()));
220257 }
221258
0 commit comments