changeset 57504:88c82777e0af

8229396: jdeps ignores multi-release when generate-module-info used on command line Reviewed-by: alanb
author mchung
date Fri, 10 Jan 2020 11:48:16 -0800
parents f7ab94fadd5a
children 91dd18044c32
files src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties test/langtools/tools/jdeps/missingDeps/MissingDepsTest.java test/langtools/tools/jdeps/missingDeps/p/internal/X.java test/langtools/tools/jdeps/missingDeps/src/m1/module-info.java test/langtools/tools/jdeps/missingDeps/src/m1/p/Foo.java test/langtools/tools/jdeps/missingDeps/src/m2/module-info.java test/langtools/tools/jdeps/missingDeps/src/m2/q/Bar.java test/langtools/tools/jdeps/missingDeps/src/m2/q/T.java
diffstat 11 files changed, 343 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Fri Jan 10 09:15:20 2020 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Fri Jan 10 11:48:16 2020 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,13 +61,6 @@
     /**
      * Returns a ClassFileReader instance of a given path.
      */
-    public static ClassFileReader newInstance(Path path) throws IOException {
-        return newInstance(path, null);
-    }
-
-    /**
-     * Returns a ClassFileReader instance of a given path.
-     */
     public static ClassFileReader newInstance(Path path, Runtime.Version version) throws IOException {
         if (Files.notExists(path)) {
             throw new FileNotFoundException(path.toString());
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Fri Jan 10 09:15:20 2020 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Fri Jan 10 11:48:16 2020 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -915,6 +915,11 @@
                             option);
                 return false;
             }
+            if (!options.rootModules.isEmpty()) {
+                reportError("err.invalid.options", "-m or --module",
+                            option);
+                return false;
+            }
             return true;
         }
 
@@ -922,12 +927,12 @@
         boolean run(JdepsConfiguration config) throws IOException {
             // check if any JAR file contains unnamed package
             for (String arg : inputArgs) {
-                try (ClassFileReader reader = ClassFileReader.newInstance(Paths.get(arg))) {
+                try (ClassFileReader reader = ClassFileReader.newInstance(Paths.get(arg), config.getVersion())) {
                     Optional<String> classInUnnamedPackage =
                         reader.entries().stream()
-                             .filter(n -> n.endsWith(".class"))
-                             .filter(cn -> toPackageName(cn).isEmpty())
-                             .findFirst();
+                              .filter(n -> n.endsWith(".class"))
+                              .filter(cn -> toPackageName(cn).isEmpty())
+                              .findFirst();
 
                     if (classInUnnamedPackage.isPresent()) {
                         if (classInUnnamedPackage.get().equals("module-info.class")) {
@@ -942,10 +947,10 @@
 
             ModuleInfoBuilder builder
                  = new ModuleInfoBuilder(config, inputArgs, dir, openModule);
-            boolean ok = builder.run();
-
-            if (!ok && !options.nowarning) {
+            boolean ok = builder.run(options.ignoreMissingDeps, log, options.nowarning);
+            if (!ok) {
                 reportError("err.missing.dependences");
+                log.println();
                 builder.visitMissingDeps(new SimpleDepVisitor());
             }
             return ok;
@@ -1041,7 +1046,7 @@
                                                                        separator);
             boolean ok = analyzer.run(options.depth(), options.ignoreMissingDeps);
             if (!ok) {
-                reportError("err.cant.list.module.deps");
+                reportError("err.missing.dependences");
                 log.println();
                 analyzer.visitMissingDeps(new SimpleDepVisitor());
             }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java	Fri Jan 10 09:15:20 2020 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java	Fri Jan 10 11:48:16 2020 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -98,7 +98,7 @@
         }
     }
 
-    public boolean run() throws IOException {
+    public boolean run(boolean ignoreMissingDeps, PrintWriter log, boolean quiet) throws IOException {
         try {
             // pass 1: find API dependencies
             Map<Archive, Set<Archive>> requiresTransitive = computeRequiresTransitive();
@@ -108,52 +108,65 @@
 
             analyzer.run(automaticModules(), dependencyFinder.locationToArchive());
 
-            boolean missingDeps = false;
             for (Module m : automaticModules()) {
                 Set<Archive> apiDeps = requiresTransitive.containsKey(m)
                                             ? requiresTransitive.get(m)
                                             : Collections.emptySet();
 
-                Path file = outputdir.resolve(m.name()).resolve("module-info.java");
+                // if this is a multi-release JAR, write to versions/$VERSION/module-info.java
+                Runtime.Version version = configuration.getVersion();
+                Path dir = version != null
+                            ? outputdir.resolve(m.name())
+                                       .resolve("versions")
+                                       .resolve(String.valueOf(version.feature()))
+                            : outputdir.resolve(m.name());
+                Path file = dir.resolve("module-info.java");
 
                 // computes requires and requires transitive
-                Module normalModule = toNormalModule(m, apiDeps);
+                Module normalModule = toNormalModule(m, apiDeps, ignoreMissingDeps);
                 if (normalModule != null) {
                     automaticToNormalModule.put(m, normalModule);
 
                     // generate module-info.java
-                    System.out.format("writing to %s%n", file);
+                    if (!quiet) {
+                        if (ignoreMissingDeps && analyzer.requires(m).anyMatch(Analyzer::notFound)) {
+                            log.format("Warning: --ignore-missing-deps specified. Missing dependencies from %s are ignored%n",
+                                       m.name());
+                        }
+                        log.format("writing to %s%n", file);
+                    }
                     writeModuleInfo(file,  normalModule.descriptor());
                 } else {
                     // find missing dependences
-                    System.out.format("Missing dependence: %s not generated%n", file);
-                    missingDeps = true;
+                    return false;
                 }
             }
 
-            return !missingDeps;
         } finally {
             dependencyFinder.shutdown();
         }
+        return true;
     }
 
-    private Module toNormalModule(Module module, Set<Archive> requiresTransitive)
+    private Module toNormalModule(Module module, Set<Archive> requiresTransitive, boolean ignoreMissingDeps)
         throws IOException
     {
         // done analysis
         module.close();
 
-        if (analyzer.requires(module).anyMatch(Analyzer::notFound)) {
+        if (!ignoreMissingDeps && analyzer.requires(module).anyMatch(Analyzer::notFound)) {
             // missing dependencies
             return null;
         }
 
         Map<String, Boolean> requires = new HashMap<>();
         requiresTransitive.stream()
+            .filter(a -> !(ignoreMissingDeps && Analyzer.notFound(a)))
             .map(Archive::getModule)
             .forEach(m -> requires.put(m.name(), Boolean.TRUE));
 
         analyzer.requires(module)
+            .filter(a -> !(ignoreMissingDeps && Analyzer.notFound(a)))
             .map(Archive::getModule)
             .forEach(d -> requires.putIfAbsent(d.name(), Boolean.FALSE));
 
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Fri Jan 10 09:15:20 2020 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Fri Jan 10 11:48:16 2020 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -229,7 +229,6 @@
 err.command.set={0} and {1} options are specified.
 err.unknown.option=unknown option: {0}
 err.missing.arg=no value given for {0}
-err.missing.dependences=missing dependencies
 err.invalid.arg.for.option=invalid argument for option: {0}
 err.option.after.class=option must be specified before classes: {0}
 err.genmoduleinfo.not.jarfile={0} is a modular JAR file that cannot be specified with the --generate-module-info option
@@ -246,8 +245,8 @@
 err.multirelease.option.notfound={0} is a multi-release jar file but --multi-release option is not set
 err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
 err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1}
-err.cant.list.module.deps=\
-Missing dependencies from the module path and classpath.\n\
+err.missing.dependences=\
+Missing dependencies: classes not found from the module path and classpath.\n\
 To suppress this error, use --ignore-missing-deps to continue.
 
 warn.invalid.arg=Path does not exist: {0}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/MissingDepsTest.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Tests jdeps option on a MR jar with missing dependences
+ * @library ../lib
+ * @build CompilerUtils JdepsUtil
+ * @modules jdk.jdeps/com.sun.tools.jdeps
+ * @run testng MissingDepsTest
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.spi.ToolProvider;
+import java.util.stream.Stream;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
+
+
+public class MissingDepsTest {
+    private static final String TEST_SRC = System.getProperty("test.src");
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path CLASSES_DIR = Paths.get("classes");
+
+    private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar").orElseThrow();
+    private static final String VERSION = "13";
+
+    private static final Set<String> modules = Set.of("m1", "m2");
+
+    /**
+     * Compiles classes used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Exception {
+        CompilerUtils.cleanDir(MODS_DIR);
+        modules.forEach(mn ->
+                assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn)));
+
+        // compile a versioned class file
+        Path versionedFile = Paths.get(TEST_SRC, "p/internal/X.java");
+        assertTrue(CompilerUtils.compile(versionedFile, CLASSES_DIR, "-cp", MODS_DIR.resolve("m2").toString()));
+
+        // create a modular multi-release m1.jar
+        JAR_TOOL.run(System.out, System.err, "cf", "m1.jar",
+                     "-C", MODS_DIR.resolve("m1").toString(), ".");
+        JAR_TOOL.run(System.out, System.err, "uf", "m1.jar",
+                     "--release", VERSION, "-C", CLASSES_DIR.toString(), "p/internal/X.class");
+        // create a non-modular multi-release mr.jar
+        JAR_TOOL.run(System.out, System.err, "cf", "mr.jar",
+                     "-C", MODS_DIR.resolve("m1").toString(), "p/Foo.class",
+                     "--release", VERSION, "-C", CLASSES_DIR.toString(), "p/internal/X.class");
+    }
+
+    @Test
+    public void genModuleInfo() {
+        JdepsTest test = new JdepsTest();
+        test.options(List.of("--generate-module-info", ".", "--multi-release", VERSION, "mr.jar"));
+        test.checkMissingDeps();
+        Path file = Paths.get("mr", "versions", VERSION, "module-info.java");
+        test.ignoreMissingDeps(file.toString());
+        assertTrue(Files.exists(file));
+    }
+
+    @Test
+    public void listModuleDeps() {
+        JdepsTest test = new JdepsTest();
+        test.options(List.of("--list-deps", "--multi-release", VERSION, "mr.jar"));
+        test.checkMissingDeps();
+        test.ignoreMissingDeps("java.management");
+    }
+
+    class JdepsTest {
+        // set DEBUG to true to show the jdeps output
+        static final boolean DEBUG = false;
+        List<String> options;
+        JdepsTest options(List<String> options) {
+            this.options = options;
+            return this;
+        }
+
+        private void checkMissingDeps() {
+            JdepsRunner jdepsRunner = new JdepsRunner(options.toArray(new String[0]));
+            int rc = jdepsRunner.run(DEBUG);
+            assertTrue(rc != 0);
+            String regex = "\\s+13/p.internal.X\\s+->\\s+q.T\\s+not found";
+            assertTrue(Arrays.stream(jdepsRunner.output()).anyMatch(l -> l.matches(regex)));
+        }
+
+        public void ignoreMissingDeps(String expected) {
+            JdepsRunner jdepsRunner = new JdepsRunner(Stream.concat(Stream.of("--ignore-missing-deps"), options.stream())
+                                                            .toArray(String[]::new));
+            int rc = jdepsRunner.run(DEBUG);
+            assertTrue(rc == 0);
+            System.out.println("Expected: " + expected);
+            assertTrue(Arrays.stream(jdepsRunner.output()).anyMatch(l -> l.contains(expected)));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/p/internal/X.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p.internal;
+
+import java.lang.management.*;
+
+class X implements q.T {
+    public void upTime() {
+        ManagementFactory.getRuntimeMXBean().getUptime();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/src/m1/module-info.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    requires static m2;
+    exports p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/src/m1/p/Foo.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class Foo implements Runnable {
+   public void run() {
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/src/m2/module-info.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports q;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/src/m2/q/Bar.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+public interface Bar {
+   default String name() {
+       return "";
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/missingDeps/src/m2/q/T.java	Fri Jan 10 11:48:16 2020 -0800
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package q;
+
+public interface T {
+}