1 /* 2 * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.lang.model; 27 28 import java.util.Collections; 29 import java.util.Set; 30 import java.util.HashSet; 31 32 /** 33 * Source versions of the Java™ programming language. 34 * 35 * See the appropriate edition of 36 * <cite>The Java™ Language Specification</cite> 37 * for information about a particular source version. 38 * 39 * <p>Note that additional source version constants will be added to 40 * model future releases of the language. 41 * 42 * @author Joseph D. Darcy 43 * @author Scott Seligman 44 * @author Peter von der Ahé 45 * @since 1.6 46 */ 47 public enum SourceVersion { 48 /* 49 * Summary of language evolution 50 * 1.1: nested classes 51 * 1.2: strictfp 52 * 1.3: no changes 53 * 1.4: assert 54 * 1.5: annotations, generics, autoboxing, var-args... 55 * 1.6: no changes 56 * 1.7: diamond syntax, try-with-resources, etc. 57 * 1.8: lambda expressions and default methods 58 * 9: modules, small cleanups to 1.7 and 1.8 changes 59 */ 60 61 /** 62 * The original version. 63 * 64 * The language described in 65 * <cite>The Java™ Language Specification, First Edition</cite>. 66 */ 67 RELEASE_0, 68 69 /** 70 * The version recognized by the Java Platform 1.1. 71 * 72 * The language is {@code RELEASE_0} augmented with nested classes as described in the 1.1 update to 73 * <cite>The Java™ Language Specification, First Edition</cite>. 74 */ 75 RELEASE_1, 76 77 /** 78 * The version recognized by the Java 2 Platform, Standard Edition, 79 * v 1.2. 80 * 81 * The language described in 82 * <cite>The Java™ Language Specification, 83 * Second Edition</cite>, which includes the {@code 84 * strictfp} modifier. 85 */ 86 RELEASE_2, 87 88 /** 89 * The version recognized by the Java 2 Platform, Standard Edition, 90 * v 1.3. 91 * 92 * No major changes from {@code RELEASE_2}. 93 */ 94 RELEASE_3, 95 96 /** 97 * The version recognized by the Java 2 Platform, Standard Edition, 98 * v 1.4. 99 * 100 * Added a simple assertion facility. 101 */ 102 RELEASE_4, 103 104 /** 105 * The version recognized by the Java 2 Platform, Standard 106 * Edition 5.0. 107 * 108 * The language described in 109 * <cite>The Java™ Language Specification, 110 * Third Edition</cite>. First release to support 111 * generics, annotations, autoboxing, var-args, enhanced {@code 112 * for} loop, and hexadecimal floating-point literals. 113 */ 114 RELEASE_5, 115 116 /** 117 * The version recognized by the Java Platform, Standard Edition 118 * 6. 119 * 120 * No major changes from {@code RELEASE_5}. 121 */ 122 RELEASE_6, 123 124 /** 125 * The version recognized by the Java Platform, Standard Edition 126 * 7. 127 * 128 * Additions in this release include, diamond syntax for 129 * constructors, {@code try}-with-resources, strings in switch, 130 * binary literals, and multi-catch. 131 * @since 1.7 132 */ 133 RELEASE_7, 134 135 /** 136 * The version recognized by the Java Platform, Standard Edition 137 * 8. 138 * 139 * Additions in this release include lambda expressions and default methods. 140 * @since 1.8 141 */ 142 RELEASE_8, 143 144 /** 145 * The version recognized by the Java Platform, Standard Edition 146 * 9. 147 * 148 * Additions in this release include modules and removal of a 149 * single underscore from the set of legal identifier names. 150 * 151 * @since 9 152 */ 153 RELEASE_9; 154 155 // Note that when adding constants for newer releases, the 156 // behavior of latest() and latestSupported() must be updated too. 157 158 /** 159 * Returns the latest source version that can be modeled. 160 * 161 * @return the latest source version that can be modeled 162 */ 163 public static SourceVersion latest() { 164 return RELEASE_9; 165 } 166 167 private static final SourceVersion latestSupported = getLatestSupported(); 168 169 private static SourceVersion getLatestSupported() { 170 try { 171 String specVersion = System.getProperty("java.specification.version"); 172 173 switch (specVersion) { 174 case "9": 175 case "1.9": 176 return RELEASE_9; 177 case "1.8": 178 return RELEASE_8; 179 case "1.7": 180 return RELEASE_7; 181 case "1.6": 182 return RELEASE_6; 183 } 184 } catch (SecurityException se) {} 185 186 return RELEASE_5; 187 } 188 189 /** 190 * Returns the latest source version fully supported by the 191 * current execution environment. {@code RELEASE_5} or later must 192 * be returned. 193 * 194 * @return the latest source version that is fully supported 195 */ 196 public static SourceVersion latestSupported() { 197 return latestSupported; 198 } 199 200 /** 201 * Returns whether or not {@code name} is a syntactically valid 202 * identifier (simple name) or keyword in the latest source 203 * version. The method returns {@code true} if the name consists 204 * of an initial character for which {@link 205 * Character#isJavaIdentifierStart(int)} returns {@code true}, 206 * followed only by characters for which {@link 207 * Character#isJavaIdentifierPart(int)} returns {@code true}. 208 * This pattern matches regular identifiers, keywords, and the 209 * literals {@code "true"}, {@code "false"}, and {@code "null"}. 210 * The method returns {@code false} for all other strings. 211 * 212 * @param name the string to check 213 * @return {@code true} if this string is a 214 * syntactically valid identifier or keyword, {@code false} 215 * otherwise. 216 */ 217 public static boolean isIdentifier(CharSequence name) { 218 String id = name.toString(); 219 220 if (id.length() == 0) { 221 return false; 222 } 223 int cp = id.codePointAt(0); 224 if (!Character.isJavaIdentifierStart(cp)) { 225 return false; 226 } 227 for (int i = Character.charCount(cp); 228 i < id.length(); 229 i += Character.charCount(cp)) { 230 cp = id.codePointAt(i); 231 if (!Character.isJavaIdentifierPart(cp)) { 232 return false; 233 } 234 } 235 return true; 236 } 237 238 /** 239 * Returns whether or not {@code name} is a syntactically valid 240 * qualified name in the latest source version. Unlike {@link 241 * #isIdentifier isIdentifier}, this method returns {@code false} 242 * for keywords and literals. 243 * 244 * @param name the string to check 245 * @return {@code true} if this string is a 246 * syntactically valid name, {@code false} otherwise. 247 * @jls 6.2 Names and Identifiers 248 */ 249 public static boolean isName(CharSequence name) { 250 return isName(name, latest()); 251 } 252 253 /** 254 * Returns whether or not {@code name} is a syntactically valid 255 * qualified name in the given source version. Unlike {@link 256 * #isIdentifier isIdentifier}, this method returns {@code false} 257 * for keywords and literals. 258 * 259 * @param name the string to check 260 * @param version the version to use 261 * @return {@code true} if this string is a 262 * syntactically valid name, {@code false} otherwise. 263 * @jls 6.2 Names and Identifiers 264 * @since 9 265 */ 266 public static boolean isName(CharSequence name, SourceVersion version) { 267 String id = name.toString(); 268 269 for(String s : id.split("\\.", -1)) { 270 if (!isIdentifier(s) || isKeyword(s, version)) 271 return false; 272 } 273 return true; 274 } 275 276 private final static Set<String> keywords; 277 static { 278 Set<String> s = new HashSet<>(); 279 String [] kws = { 280 "abstract", "continue", "for", "new", "switch", 281 "assert", "default", "if", "package", "synchronized", 282 "boolean", "do", "goto", "private", "this", 283 "break", "double", "implements", "protected", "throw", 284 "byte", "else", "import", "public", "throws", 285 "case", "enum", "instanceof", "return", "transient", 286 "catch", "extends", "int", "short", "try", 287 "char", "final", "interface", "static", "void", 288 "class", "finally", "long", "strictfp", "volatile", 289 "const", "float", "native", "super", "while", 290 // literals 291 "null", "true", "false", 292 "_" // keyword as of 9 293 }; 294 for(String kw : kws) 295 s.add(kw); 296 keywords = Collections.unmodifiableSet(s); 297 } 298 299 /** 300 * Returns whether or not {@code s} is a keyword or literal in the 301 * latest source version. 302 * 303 * @param s the string to check 304 * @return {@code true} if {@code s} is a keyword or literal, {@code false} otherwise. 305 */ 306 public static boolean isKeyword(CharSequence s) { 307 return keywords.contains(s.toString()); 308 } 309 310 /** 311 * Returns whether or not {@code s} is a keyword or literal in the 312 * given source version. 313 * 314 * @param s the string to check 315 * @param version the version to use 316 * @return {@code true} if {@code s} is a keyword or literal, {@code false} otherwise. 317 * @since 9 318 */ 319 public static boolean isKeyword(CharSequence s, SourceVersion version) { 320 String id = s.toString(); 321 if ("_".equals(id)) { 322 return version.compareTo(RELEASE_9) >= 0; 323 } else { 324 return keywords.contains(id); 325 } 326 } 327 }