diff options
| author | Till Brychcy | 2017-08-21 20:55:02 +0000 |
|---|---|---|
| committer | Till Brychcy | 2017-08-22 14:49:45 +0000 |
| commit | 11440724633ebdd48c66529dcb36255176b80893 (patch) | |
| tree | 5039c223474117658e8fdb52720ca7f043c5161c | |
| parent | 626e9535193b84dff52b8aaccc65c4259eb9bc59 (diff) | |
| download | eclipse.jdt.core-11440724633ebdd48c66529dcb36255176b80893.tar.gz eclipse.jdt.core-11440724633ebdd48c66529dcb36255176b80893.tar.xz eclipse.jdt.core-11440724633ebdd48c66529dcb36255176b80893.zip | |
Change-Id: I3842f51b73f0dff7b453e13cb31267edecc3f803
4 files changed, 230 insertions, 12 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java new file mode 100644 index 0000000000..4f7bf13b4d --- /dev/null +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2017 Till Brychcy and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Till Brychcy - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.tests.compiler.regression; + +import static org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming.determineAutomaticModuleName; +import static org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming.determineAutomaticModuleNameFromFileName; + +import java.io.File; + +import org.eclipse.jdt.core.tests.util.Util; + +import junit.framework.Test; + +public class AutomaticModuleNamingTest extends AbstractRegressionTest { + static { + // TESTS_NAMES = new String[] { "testManifest" }; + } + + public AutomaticModuleNamingTest(String name) { + super(name); + } + + public static Test suite() { + return buildMinimalComplianceTestSuite(testClass(), F_1_8); + } + + public static Class<?> testClass() { + return AutomaticModuleNamingTest.class; + } + + public void testManifest() throws Exception { + String dirName = OUTPUT_DIR + File.separator + "automatic"; + try { + String metaInfDir = dirName + File.separator + "META-INF"; + new File(metaInfDir).mkdirs(); + + Util.createFile(metaInfDir + File.separator + "MANIFEST.MF", // + "Manifest-Version: 1.0\n" // + + "Automatic-Module-Name: module.123\n"); + Util.zip(new File(dirName), dirName + File.separator + "foo.bar-1.2.3.jar"); + assertEquals("module.123", new String( + determineAutomaticModuleName((dirName + File.separator + "foo.bar-1.2.3.jar").toString()))); + } finally { + Util.delete(dirName); + } + } + + public void testSimple() throws Exception { + assertEquals("junit", new String(determineAutomaticModuleNameFromFileName("junit.jar", false, true))); + } + + public void testWithVersion() throws Exception { + assertEquals("junit", new String(determineAutomaticModuleNameFromFileName("junit-4.8.2.jar", false, true))); + } + + public void testMultiParts() throws Exception { + assertEquals("foo.bar", new String(determineAutomaticModuleNameFromFileName("foo-bar.jar", false, true))); + } + + public void testMultiPartWithVersion() throws Exception { + assertEquals("foo.bar", + new String(determineAutomaticModuleNameFromFileName("foo-bar-1.2.3-SNAPSHOT.jar", false, true))); + } + + public void testMultiPartWithNumberWithoutDot() throws Exception { + assertEquals("foo.bar.3d", + new String(determineAutomaticModuleNameFromFileName("foo-bar-3d-1.2.3-SNAPSHOT.jar", false, true))); + } + + public void testSpecialCharacters() throws Exception { + assertEquals("foo.bar", + new String(determineAutomaticModuleNameFromFileName("?foo?bar?-1.2.3-SNAPSHOT.jar", false, true))); + } + + public void testMultipleSpecialCharacters() throws Exception { + assertEquals("foo.bar", new String( + determineAutomaticModuleNameFromFileName("?@#foo?@#bar?@#-1.2.3-SNAPSHOT.jar", false, true))); + } + + public void testMultipleSpecialCharactersWithDirectory() throws Exception { + assertEquals("foo.bar.bla", + new String(determineAutomaticModuleNameFromFileName( + File.separator + "somedir" + File.separator + "?@#foo?@#bar?@#bla?@#-1.2.3-SNAPSHOT.jar", true, + true))); + } + + public void testFileEndsWithDotJar() throws Exception { + assertEquals("module.jar", new String( + determineAutomaticModuleNameFromFileName("somedir" + File.separator + "module.jar.jar", true, true))); + } + + public void testProjectNameEndsWithDotJar() throws Exception { + // for hypothetical use case: project on module path treated as automatic module + assertEquals("module.jar", new String( + determineAutomaticModuleNameFromFileName("somedir" + File.separator + "module.jar", true, false))); + } + + public void testUPPERCASE() throws Exception { + // upper case .JAR isn't mentioned in the spec, but currently handled like .jar + assertEquals("FOO.BAR", new String(determineAutomaticModuleNameFromFileName("FOO-BAR.JAR", true, true))); + } + + public void testZip() throws Exception { + // .ZIP isn't mentioned in the spec. + assertEquals("CLASSES12.ZIP", + new String(determineAutomaticModuleNameFromFileName("CLASSES12.ZIP", true, true))); + } + +} diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java index 246467b711..fb9a98b100 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java @@ -164,6 +164,7 @@ public static Test suite() { since_9.add(InterfaceMethodsTest_9.class); since_9.add(Deprecated9Test.class); since_9.add(ModuleAttributeTests.class); + since_9.add(AutomaticModuleNamingTest.class); // Build final test suite TestSuite all = new TestSuite(TestAll.class.getName()); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java new file mode 100644 index 0000000000..63ba2d8816 --- /dev/null +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2017 Till Brychcy and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Till Brychcy - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.env; + +import java.io.File; +import java.io.IOException; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class AutomaticModuleNaming { + /* + * Determine the automatic module name as specified in {@link <a href= + * "http://download.java.net/java/jdk9/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-"> + * ModuleFinder.of</a>} + */ + public static char[] determineAutomaticModuleName(final String jarFileName) { + // "If the JAR file has the attribute "Automatic-Module-Name" in its main manifest then its value is the + // module name." + try (JarFile jar = new JarFile(jarFileName)) { + Manifest manifest = jar.getManifest(); + if (manifest != null) { + String automaticModuleName = manifest.getMainAttributes().getValue("Automatic-Module-Name"); //$NON-NLS-1$ + if (automaticModuleName != null) { + return automaticModuleName.toCharArray(); + } + } + } catch (IOException e) { + // ignore + } + // The module name is otherwise derived from the name of the JAR file. + return determineAutomaticModuleNameFromFileName(jarFileName, true, true); + } + + /** + * Determine the automatic module name if no "Automatic-Module-Name" was found in the Manifest, as specified in + * {@link <a href= + * "http://download.java.net/java/jdk9/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-">ModuleFinder.of</a>} + * + * @param name + * the filename (or directory name) + * @param skipDirectory + * if true, parent directory names are skipped + * @param removeExtension + * if true, the ".jar" extension is removed. + */ + public static char[] determineAutomaticModuleNameFromFileName(String name, boolean skipDirectory, + boolean removeExtension) { + int index; + int start = 0; + int end = name.length(); + if (skipDirectory) { + index = name.lastIndexOf(File.separatorChar); + start = index + 1; + } + + // "The ".jar" suffix is removed" + if (removeExtension) { + if (name.endsWith(".jar") || name.endsWith(".JAR")) { //$NON-NLS-1$//$NON-NLS-2$ + end -= 4; + } + } + + // "If the name matches the regular expression "-(\\d+(\\.|$))" then the module name will be derived from the + // subsequence preceding the hyphen of the first occurrence. [...]" + dashLoop: for (index = start; index < end - 1; index++) { + if (name.charAt(index) == '-' && name.charAt(index + 1) >= '0' && name.charAt(index + 1) <= '9') { + for (int index2 = index + 2; index2 < end; index2++) { + final char c = name.charAt(index2 + 1); + if (c == '.') { + break; + } + if (c < '0' || c > '9') { + continue dashLoop; + } + } + end = index; + break; + } + } + + // "All non-alphanumeric characters ([^A-Za-z0-9]) in the module name are replaced with a dot ("."), all + // repeating dots are replaced with one dot, and all leading and trailing dots are removed." + StringBuilder sb = new StringBuilder(end - start); + boolean needDot = false; + for (int i = start; i < end; i++) { + char c = name.charAt(i); + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { + if (needDot) { + sb.append('.'); + needDot = false; + } + sb.append(c); + } else { + if (sb.length() > 0) { + needDot = true; + } + } + } + return sb.toString().toCharArray(); + } + +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java index c326b2a232..0d10a6f778 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java @@ -15,10 +15,9 @@ package org.eclipse.jdt.internal.core.builder; -import java.io.File; - import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.env.IModulePathEntry; import org.eclipse.jdt.internal.compiler.lookup.AutoModule; @@ -62,17 +61,8 @@ public class ModulePathEntry implements IModulePathEntry { return this.isAutomaticModule; } public static char[] getAutomaticModuleName(ClasspathLocation location) { - String name = null; if (location instanceof ClasspathJar) { - name = ((ClasspathJar) location).zipFilename; - int index = name.lastIndexOf('.'); - if (index != -1) - name = name.substring(0, index); - index = name.lastIndexOf(File.separatorChar); - if (index == -1) - return name.toCharArray(); - return name.substring(index + 1).toCharArray(); - + return AutomaticModuleNaming.determineAutomaticModuleName(((ClasspathJar) location).zipFilename); } if (location instanceof ClasspathDirectory) { return ((ClasspathDirectory) location).binaryFolder.getName().toCharArray(); |
