mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-21 20:30:39 +00:00
8164805: Fail to create a MR modular JAR with a versioned entry of a concealed package
Reviewed-by: chegar, mchung
This commit is contained in:
parent
1552f3ddbb
commit
5530ec2227
@ -80,6 +80,7 @@ class Main {
|
||||
String fname, mname, ename;
|
||||
String zname = "";
|
||||
String rootjar = null;
|
||||
Set<String> concealedPackages = new HashSet<>();
|
||||
|
||||
private static final int BASE_VERSION = 0;
|
||||
|
||||
@ -821,22 +822,21 @@ class Main {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Set<String> findPackages(ZipFile zf) {
|
||||
return zf.stream()
|
||||
.filter(e -> e.getName().endsWith(".class"))
|
||||
.map(e -> toPackageName(e))
|
||||
.filter(pkg -> pkg.length() > 0)
|
||||
.distinct()
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static String toPackageName(ZipEntry entry) {
|
||||
return toPackageName(entry.getName());
|
||||
}
|
||||
|
||||
private static String toPackageName(String path) {
|
||||
assert path.endsWith(".class");
|
||||
int index = path.lastIndexOf('/');
|
||||
int index;
|
||||
if (path.startsWith(VERSIONS_DIR)) {
|
||||
index = path.indexOf('/', VERSIONS_DIR.length());
|
||||
if (index <= 0) {
|
||||
return "";
|
||||
}
|
||||
path = path.substring(index + 1);
|
||||
}
|
||||
index = path.lastIndexOf('/');
|
||||
if (index != -1) {
|
||||
return path.substring(0, index).replace('/', '.');
|
||||
} else {
|
||||
@ -875,7 +875,7 @@ class Main {
|
||||
entryMap.put(entryName, entry);
|
||||
} else if (entries.add(entry)) {
|
||||
jarEntries.add(entryName);
|
||||
if (entry.basename.endsWith(".class") && !entryName.startsWith(VERSIONS_DIR))
|
||||
if (entry.basename.endsWith(".class"))
|
||||
packages.add(toPackageName(entry.basename));
|
||||
if (isUpdate)
|
||||
entryMap.put(entryName, entry);
|
||||
@ -1068,7 +1068,7 @@ class Main {
|
||||
}
|
||||
|
||||
jarEntries.add(name);
|
||||
if (name.endsWith(".class") && !(name.startsWith(VERSIONS_DIR)))
|
||||
if (name.endsWith(".class"))
|
||||
packages.add(toPackageName(name));
|
||||
}
|
||||
}
|
||||
@ -1761,6 +1761,13 @@ class Main {
|
||||
err.println(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a warning message
|
||||
*/
|
||||
void warn(String s) {
|
||||
err.println(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main routine to start program.
|
||||
*/
|
||||
@ -1975,24 +1982,30 @@ class Main {
|
||||
ByteBuffer bb = ByteBuffer.wrap(moduleInfos.get(MODULE_INFO));
|
||||
ModuleDescriptor rd = ModuleDescriptor.read(bb);
|
||||
|
||||
Set<String> exports = rd.exports()
|
||||
.stream()
|
||||
.map(Exports::source)
|
||||
.collect(toSet());
|
||||
|
||||
Set<String> conceals = packages.stream()
|
||||
.filter(p -> !exports.contains(p))
|
||||
.collect(toSet());
|
||||
concealedPackages = findConcealedPackages(rd);
|
||||
|
||||
for (Map.Entry<String,byte[]> e: moduleInfos.entrySet()) {
|
||||
ModuleDescriptor vd = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
|
||||
if (!(isValidVersionedDescriptor(vd, rd)))
|
||||
return false;
|
||||
e.setValue(extendedInfoBytes(rd, vd, e.getValue(), conceals));
|
||||
e.setValue(extendedInfoBytes(rd, vd, e.getValue(), concealedPackages));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<String> findConcealedPackages(ModuleDescriptor md){
|
||||
Objects.requireNonNull(md);
|
||||
|
||||
Set<String> exports = md.exports()
|
||||
.stream()
|
||||
.map(Exports::source)
|
||||
.collect(toSet());
|
||||
|
||||
return packages.stream()
|
||||
.filter(p -> !exports.contains(p))
|
||||
.collect(toSet());
|
||||
}
|
||||
|
||||
private static boolean isPlatformModule(String name) {
|
||||
return name.startsWith("java.") || name.startsWith("jdk.");
|
||||
}
|
||||
|
||||
@ -152,9 +152,13 @@ final class Validator implements Consumer<JarEntry> {
|
||||
return;
|
||||
}
|
||||
if (fp.isPublicClass()) {
|
||||
main.error(Main.formatMsg("error.validator.new.public.class", entryName));
|
||||
isValid = false;
|
||||
return;
|
||||
if (!isConcealed(internalName)) {
|
||||
main.error(Main.formatMsg("error.validator.new.public.class", entryName));
|
||||
isValid = false;
|
||||
return;
|
||||
}
|
||||
main.warn(Main.formatMsg("warn.validator.concealed.public.class", entryName));
|
||||
debug("%s is a public class entry in a concealed package", entryName);
|
||||
}
|
||||
debug("%s is a non-public class entry", entryName);
|
||||
fps.put(internalName, fp);
|
||||
@ -169,7 +173,7 @@ final class Validator implements Consumer<JarEntry> {
|
||||
|
||||
// are the two classes/resources identical?
|
||||
if (fp.isIdentical(matchFp)) {
|
||||
main.error(Main.formatMsg("error.validator.identical.entry", entryName));
|
||||
main.warn(Main.formatMsg("warn.validator.identical.entry", entryName));
|
||||
return; // it's okay, just takes up room
|
||||
}
|
||||
debug("sha1 not equal -- different bytes");
|
||||
@ -204,7 +208,7 @@ final class Validator implements Consumer<JarEntry> {
|
||||
}
|
||||
debug("%s is a resource", entryName);
|
||||
|
||||
main.error(Main.formatMsg("error.validator.resources.with.same.name", entryName));
|
||||
main.warn(Main.formatMsg("warn.validator.resources.with.same.name", entryName));
|
||||
fps.put(internalName, fp);
|
||||
return;
|
||||
}
|
||||
@ -235,6 +239,15 @@ final class Validator implements Consumer<JarEntry> {
|
||||
return entryName.endsWith(".class") ? entryName.substring(0, entryName.length() - 6) : null;
|
||||
}
|
||||
|
||||
private boolean isConcealed(String internalName) {
|
||||
if (main.concealedPackages.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
int idx = internalName.lastIndexOf('/');
|
||||
String pkgName = idx != -1 ? internalName.substring(0, idx).replace('/', '.') : "";
|
||||
return main.concealedPackages.contains(pkgName);
|
||||
}
|
||||
|
||||
private void debug(String fmt, Object... args) {
|
||||
if (DEBUG) System.err.format(fmt, args);
|
||||
}
|
||||
|
||||
@ -99,16 +99,19 @@ error.validator.isolated.nested.class=\
|
||||
entry: {0}, is an isolated nested class
|
||||
error.validator.new.public.class=\
|
||||
entry: {0}, contains a new public class not found in base entries
|
||||
error.validator.identical.entry=\
|
||||
warning - entry: {0} contains a class that is identical to an entry already in the jar
|
||||
error.validator.incompatible.class.version=\
|
||||
entry: {0}, has a class version incompatible with an earlier version
|
||||
error.validator.different.api=\
|
||||
entry: {0}, contains a class with different api from earlier version
|
||||
error.validator.resources.with.same.name=\
|
||||
warning - entry: {0}, multiple resources with same name
|
||||
error.validator.names.mismatch=\
|
||||
entry: {0}, contains a class with internal name {1}, names do not match
|
||||
warn.validator.identical.entry=\
|
||||
warning - entry: {0} contains a class that is identical to an entry already in the jar
|
||||
warn.validator.resources.with.same.name=\
|
||||
warning - entry: {0}, multiple resources with same name
|
||||
warn.validator.concealed.public.class=\
|
||||
warning - entry {0} is a public class in a concealed package, \n\
|
||||
placing this jar on the class path will result in incompatible public interfaces
|
||||
out.added.manifest=\
|
||||
added manifest
|
||||
out.added.module-info=\
|
||||
|
||||
225
jdk/test/tools/jar/mmrjar/ConcealedPackage.java
Normal file
225
jdk/test/tools/jar/mmrjar/ConcealedPackage.java
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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
|
||||
* @bug 8146486
|
||||
* @summary Fail to create a MR modular JAR with a versioned entry in
|
||||
* base-versioned empty package
|
||||
* @library /lib/testlibrary
|
||||
* @build jdk.testlibrary.FileUtils
|
||||
* @run testng ConcealedPackage
|
||||
*/
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.testlibrary.FileUtils;
|
||||
|
||||
public class ConcealedPackage {
|
||||
private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
|
||||
.orElseThrow(() -> new RuntimeException("jar tool not found"));
|
||||
private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")
|
||||
.orElseThrow(() -> new RuntimeException("javac tool not found"));
|
||||
private final String linesep = System.lineSeparator();
|
||||
private final Path userdir;
|
||||
private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
|
||||
private final PrintStream out = new PrintStream(outbytes, true);
|
||||
private final ByteArrayOutputStream errbytes = new ByteArrayOutputStream();
|
||||
private final PrintStream err = new PrintStream(errbytes, true);
|
||||
|
||||
public ConcealedPackage() throws IOException {
|
||||
Path testsrc = Paths.get(System.getProperty("test.src"));
|
||||
userdir = Paths.get(System.getProperty("user.dir", "."));
|
||||
|
||||
// compile the classes directory
|
||||
Path source = testsrc.resolve("src").resolve("classes");
|
||||
Path destination = Paths.get("classes");
|
||||
javac(source, destination);
|
||||
|
||||
// compile the mr9 directory including module-info.java
|
||||
source = testsrc.resolve("src").resolve("mr9");
|
||||
destination = Paths.get("mr9");
|
||||
javac(source, destination);
|
||||
|
||||
// move module-info.class for later use
|
||||
Files.move(destination.resolve("module-info.class"),
|
||||
Paths.get("module-info.class"));
|
||||
}
|
||||
|
||||
private void javac(Path source, Path destination) throws IOException {
|
||||
String[] args = Stream.concat(
|
||||
Stream.of("-d", destination.toString()),
|
||||
Files.walk(source)
|
||||
.map(Path::toString)
|
||||
.filter(s -> s.endsWith(".java"))
|
||||
).toArray(String[]::new);
|
||||
JAVAC_TOOL.run(System.out, System.err, args);
|
||||
}
|
||||
|
||||
private int jar(String cmd) {
|
||||
outbytes.reset();
|
||||
errbytes.reset();
|
||||
return JAR_TOOL.run(out, err, cmd.split(" +"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public void cleanup() throws IOException {
|
||||
Files.walk(userdir, 1)
|
||||
.filter(p -> !p.equals(userdir))
|
||||
.forEach(p -> {
|
||||
try {
|
||||
if (Files.isDirectory(p)) {
|
||||
FileUtils.deleteFileTreeWithRetry(p);
|
||||
} else {
|
||||
FileUtils.deleteFileIfExistsWithRetry(p);
|
||||
}
|
||||
} catch (IOException x) {
|
||||
throw new UncheckedIOException(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// updates a valid multi-release jar with a new public class in
|
||||
// versioned section and fails
|
||||
@Test
|
||||
public void test1() {
|
||||
// successful build of multi-release jar
|
||||
int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
|
||||
Assert.assertEquals(rc, 0);
|
||||
|
||||
jar("-tf mmr.jar");
|
||||
|
||||
String s = new String(outbytes.toByteArray());
|
||||
Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
|
||||
Set<String> expected = Set.of(
|
||||
"META-INF/",
|
||||
"META-INF/MANIFEST.MF",
|
||||
"p/",
|
||||
"p/Hi.class",
|
||||
"META-INF/versions/9/p/Hi.class"
|
||||
);
|
||||
Assert.assertEquals(actual, expected);
|
||||
|
||||
// failed build because of new public class
|
||||
rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");
|
||||
Assert.assertEquals(rc, 1);
|
||||
|
||||
s = new String(errbytes.toByteArray());
|
||||
Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public "
|
||||
+ "class not found in base entries")
|
||||
);
|
||||
}
|
||||
|
||||
// updates a valid multi-release jar with a module-info class and new
|
||||
// concealed public class in versioned section and succeeds
|
||||
@Test
|
||||
public void test2() {
|
||||
// successful build of multi-release jar
|
||||
int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
|
||||
Assert.assertEquals(rc, 0);
|
||||
|
||||
// successful build because of module-info and new public class
|
||||
rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class");
|
||||
Assert.assertEquals(rc, 0);
|
||||
|
||||
String s = new String(errbytes.toByteArray());
|
||||
Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a "
|
||||
+ "concealed package, \nplacing this jar on the class path "
|
||||
+ "will result in incompatible public interfaces")
|
||||
);
|
||||
|
||||
jar("-tf mmr.jar");
|
||||
|
||||
s = new String(outbytes.toByteArray());
|
||||
Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
|
||||
Set<String> expected = Set.of(
|
||||
"META-INF/",
|
||||
"META-INF/MANIFEST.MF",
|
||||
"p/",
|
||||
"p/Hi.class",
|
||||
"META-INF/versions/9/p/Hi.class",
|
||||
"META-INF/versions/9/p/internal/Bar.class",
|
||||
"module-info.class"
|
||||
);
|
||||
Assert.assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
// jar tool fails building mmr.jar because of new public class
|
||||
@Test
|
||||
public void test3() {
|
||||
int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 .");
|
||||
Assert.assertEquals(rc, 1);
|
||||
|
||||
String s = new String(errbytes.toByteArray());
|
||||
Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public "
|
||||
+ "class not found in base entries")
|
||||
);
|
||||
}
|
||||
|
||||
// jar tool succeeds building mmr.jar because of concealed package
|
||||
@Test
|
||||
public void test4() {
|
||||
int rc = jar("-cf mmr.jar module-info.class -C classes . " +
|
||||
"--release 9 module-info.class -C mr9 .");
|
||||
Assert.assertEquals(rc, 0);
|
||||
|
||||
String s = new String(errbytes.toByteArray());
|
||||
Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a "
|
||||
+ "concealed package, \nplacing this jar on the class path "
|
||||
+ "will result in incompatible public interfaces")
|
||||
);
|
||||
|
||||
jar("-tf mmr.jar");
|
||||
|
||||
s = new String(outbytes.toByteArray());
|
||||
Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
|
||||
Set<String> expected = Set.of(
|
||||
"META-INF/",
|
||||
"META-INF/MANIFEST.MF",
|
||||
"module-info.class",
|
||||
"META-INF/versions/9/module-info.class",
|
||||
"p/",
|
||||
"p/Hi.class",
|
||||
"META-INF/versions/9/p/",
|
||||
"META-INF/versions/9/p/Hi.class",
|
||||
"META-INF/versions/9/p/internal/",
|
||||
"META-INF/versions/9/p/internal/Bar.class"
|
||||
);
|
||||
Assert.assertEquals(actual, expected);
|
||||
}
|
||||
}
|
||||
30
jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java
Normal file
30
jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 Hi {
|
||||
public void sayHi() {
|
||||
System.out.println("Hi");
|
||||
}
|
||||
}
|
||||
27
jdk/test/tools/jar/mmrjar/src/mr9/module-info.java
Normal file
27
jdk/test/tools/jar/mmrjar/src/mr9/module-info.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 {
|
||||
exports p;
|
||||
}
|
||||
|
||||
30
jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java
Normal file
30
jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 Hi {
|
||||
public void sayHi() {
|
||||
System.out.println("Hello");
|
||||
}
|
||||
}
|
||||
31
jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java
Normal file
31
jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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;
|
||||
|
||||
public class Bar {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "p.internal.Bar";
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user