--- a/java.source/src/org/netbeans/modules/java/source/parsing/JavacParser.java Fri Apr 12 14:06:09 2013 +0200 +++ a/java.source/src/org/netbeans/modules/java/source/parsing/JavacParser.java Sun Apr 14 21:24:06 2013 +0200 @@ -871,10 +871,11 @@ return task; } - private static @NonNull com.sun.tools.javac.code.Source validateSourceLevel( + static @NonNull com.sun.tools.javac.code.Source validateSourceLevel( @NullAllowed String sourceLevel, @NonNull final ClasspathInfo cpInfo) { ClassPath bootClassPath = cpInfo.getClassPath(PathKind.BOOT); + ClassPath classPath = null; ClassPath srcClassPath = cpInfo.getClassPath(PathKind.SOURCE); com.sun.tools.javac.code.Source[] sources = com.sun.tools.javac.code.Source.values(); Level warnLevel; @@ -889,23 +890,31 @@ if (source.name.equals(sourceLevel)) { if (source.compareTo(com.sun.tools.javac.code.Source.JDK1_4) >= 0) { if (bootClassPath != null && bootClassPath.findResource("java/lang/AssertionError.class") == null) { //NOI18N - if (srcClassPath != null && srcClassPath.findResource("java/lang/AssertionError.java") == null) { - LOGGER.log(warnLevel, - "Even though the source level of {0} is set to: {1}, java.lang.AssertionError cannot be found on the bootclasspath: {2}\n" + - "Changing source level to 1.3", - new Object[]{cpInfo.getClassPath(PathKind.SOURCE), sourceLevel, bootClassPath}); //NOI18N - return com.sun.tools.javac.code.Source.JDK1_3; + if (bootClassPath.findResource("java/lang/Object.class") == null) { // NOI18N + // empty bootClassPath also check classpath + classPath = cpInfo.getClassPath(PathKind.COMPILE); + } + if (srcClassPath != null && srcClassPath.findResource("java/lang/AssertionError.java") == null) { // NOI18N + if (classPath == null || classPath.findResource("java/lang/AssertionError.class") == null) { // NOI18N + LOGGER.log(warnLevel, + "Even though the source level of {0} is set to: {1}, java.lang.AssertionError cannot be found on the bootclasspath: {2}\n" + + "Changing source level to 1.3", + new Object[]{cpInfo.getClassPath(PathKind.SOURCE), sourceLevel, bootClassPath}); //NOI18N + return com.sun.tools.javac.code.Source.JDK1_3; + } } } } if (source.compareTo(com.sun.tools.javac.code.Source.JDK1_5) >= 0) { if (bootClassPath != null && bootClassPath.findResource("java/lang/StringBuilder.class") == null) { //NOI18N if (srcClassPath != null && srcClassPath.findResource("java/lang/StringBuilder.java")==null) { - LOGGER.log(warnLevel, - "Even though the source level of {0} is set to: {1}, java.lang.StringBuilder cannot be found on the bootclasspath: {2}\n" + - "Changing source level to 1.4", - new Object[]{cpInfo.getClassPath(PathKind.SOURCE), sourceLevel, bootClassPath}); //NOI18N - return com.sun.tools.javac.code.Source.JDK1_4; + if (classPath == null || classPath.findResource("java/lang/StringBuilder.class") == null) { // NOI18N + LOGGER.log(warnLevel, + "Even though the source level of {0} is set to: {1}, java.lang.StringBuilder cannot be found on the bootclasspath: {2}\n" + + "Changing source level to 1.4", + new Object[]{cpInfo.getClassPath(PathKind.SOURCE), sourceLevel, bootClassPath}); //NOI18N + return com.sun.tools.javac.code.Source.JDK1_4; + } } } } --- a/java.source/test/unit/src/org/netbeans/modules/java/source/parsing/JavacParserTest.java Fri Apr 12 14:06:09 2013 +0200 +++ a/java.source/test/unit/src/org/netbeans/modules/java/source/parsing/JavacParserTest.java Sun Apr 14 21:24:06 2013 +0200 @@ -46,7 +46,12 @@ import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import com.sun.source.util.TreePathScanner; +import com.sun.tools.javac.code.Source; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -54,6 +59,8 @@ import javax.lang.model.element.TypeElement; import javax.swing.text.Document; import javax.tools.Diagnostic; +import static junit.framework.Assert.assertEquals; +import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.lexer.JavaTokenId; import org.netbeans.api.java.source.ClasspathInfo; import org.netbeans.api.java.source.CompilationController; @@ -67,6 +74,7 @@ import org.netbeans.api.lexer.TokenSequence; import org.netbeans.junit.NbTestCase; import org.netbeans.modules.java.source.tasklist.CompilerSettings; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.openide.cookies.EditorCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -284,6 +292,60 @@ }, true); } + public void testIfMissingObjectOnBootCPUseCPToGuessSourceLevel() throws Exception { + Source ret = guessSourceLevel(false, false); + assertEquals("Downgraded to 1.4", Source.JDK1_4, ret); + } + + public void testIfObjectPresentOnBootDontUseCPToGuessSourceLevel() throws Exception { + Source ret = guessSourceLevel(true, false); + assertEquals("Downgraded to 1.4, as Object on bootCP, but no AssertError", Source.JDK1_3, ret); + } + + public void testIfMissingObjectOnBootCPUseCPToGuessSourceLevelWithStringBuilder() throws Exception { + Source ret = guessSourceLevel(false, true); + assertEquals("Kept to 1.7", Source.JDK1_7, ret); + } + + private Source guessSourceLevel(boolean objectOnBCP, boolean sbOnCP) throws Exception { + clearWorkDir(); + File bcp = new File(getWorkDir(), "bootcp"); + bcp.mkdirs(); + + File cp = new File(getWorkDir(), "cp"); + cp.mkdirs(); + + File src = new File(getWorkDir(), "src"); + src.mkdirs(); + + if (objectOnBCP) { + copyResource( + JavacParserTest.class.getResource("/java/lang/Object.class"), + new File(new File(new File(bcp, "java"), "lang"), "Object.class") + ); + } + + copyResource( + JavacParserTest.class.getResource("/java/lang/AssertionError.class"), + new File(new File(new File(cp, "java"), "lang"), "AssertionError.class") + ); + + if (sbOnCP) { + copyResource( + JavacParserTest.class.getResource("/java/lang/StringBuilder.class"), + new File(new File(new File(cp, "java"), "lang"), "StringBuilder.class") + ); + } + + ClasspathInfo info = ClasspathInfo.create( + ClassPathSupport.createClassPath(bcp.toURI().toURL()), + ClassPathSupport.createClassPath(cp.toURI().toURL()), + ClassPathSupport.createClassPath(src.toURI().toURL()) + ); + + return JavacParser.validateSourceLevel("1.7", info); + } + private FileObject createFile(String path, String content) throws Exception { FileObject file = FileUtil.createData(sourceRoot, path); TestUtilities.copyStringToFile(file, content); @@ -305,4 +367,15 @@ SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cache); } + private static void copyResource(URL resource, File file) throws IOException { + assertNotNull("Resource found", resource); + file.getParentFile().mkdirs(); + assertTrue("New file " + file + " created", file.createNewFile()); + FileOutputStream os = new FileOutputStream(file); + InputStream is = resource.openStream(); + FileUtil.copy(is, os); + is.close(); + os.close(); + } + }