Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTill Brychcy2017-08-21 20:55:02 +0000
committerTill Brychcy2017-08-22 14:49:45 +0000
commit11440724633ebdd48c66529dcb36255176b80893 (patch)
tree5039c223474117658e8fdb52720ca7f043c5161c
parent626e9535193b84dff52b8aaccc65c4259eb9bc59 (diff)
downloadeclipse.jdt.core-11440724633ebdd48c66529dcb36255176b80893.tar.gz
eclipse.jdt.core-11440724633ebdd48c66529dcb36255176b80893.tar.xz
eclipse.jdt.core-11440724633ebdd48c66529dcb36255176b80893.zip
Bug 515932 - [9] Implement naming of automatic modules as per spec
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java117
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java1
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java110
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModulePathEntry.java14
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();

Back to the top