0

I'm curious what would happen if I create the exact same package that exists in an API that the project has (e.g. java.util from core Java API). Would the compiler give me an error or something?

If the compiler allows this, what would happen if I create a class with a name that the original API has?

Also, does that mean that package-private fields and methods are accessible if the compiler doesn't complain?

Jai
  • 8,165
  • 2
  • 21
  • 52
  • 5
    Maybe you could start by trying it out and reporting at least partial results here? – Andrey Tyukin Mar 01 '18 at 01:26
  • 1
    Possible duplicate of [Possible to use two java classes with same name and same package?](https://stackoverflow.com/questions/6879652/possible-to-use-two-java-classes-with-same-name-and-same-package) – Jorge Campos Mar 01 '18 at 01:28
  • @JorgeCampos That question seems more for adding 2 API with conflicting package/name to the project. It may be closely related but I don't think these two questions are similar enough. – Jai Mar 01 '18 at 02:08

3 Answers3

3

I was curious enough that I did my own testing. I created java.util.concurrent and created a Test class with this method:

public static Object getResult(CompletableFuture<?> cf) {
    return cf.result;
}

Then I called it somewhere else in a main method. There is no compile error. Running that causes this:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.util.concurrent at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662) at java.lang.ClassLoader.defineClass(ClassLoader.java:761) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) at java.net.URLClassLoader.access$100(URLClassLoader.java:73) at java.net.URLClassLoader$1.run(URLClassLoader.java:368) at java.net.URLClassLoader$1.run(URLClassLoader.java:362) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:361) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

So, it does seem like it has to do with classloader... or so I thought... Until I took a look at ClassLoader.preDefineClass():

// Note:  Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
// relies on the fact that spoofing is impossible if a class has a name
// of the form "java.*"
if ((name != null) && name.startsWith("java.")) {
    throw new SecurityException
        ("Prohibited package name: " +
         name.substring(0, name.lastIndexOf('.')));
}

So, it's stopping me because Java wants to protect all the packages starting with java!

I went and tried something else. I added javafx.scene package and another Test class with this method:

public static boolean getBoundsChange(Node n) {
    return n.boundsChanged;
}

Again, there is no compile errors, but it throws this at runtime:

Caused by: java.lang.IllegalAccessError: tried to access field javafx.scene.Node.boundsChanged from class javafx.scene.TestNode at javafx.scene.TestNode.getBoundsChange(TestNode.java:7) at testFX.start(testFX.java:29) at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863) at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326) at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) ... 1 more

Seems like Java does protect against these, but does so only at runtime.

I created another interface in javafx.scene and just let it extend Consumer<T>. I can use it just like the original Consumer<T>, so there is nothing stopping me from using that package for my new classes.

Jai
  • 8,165
  • 2
  • 21
  • 52
  • 1
    It might be VM dependent, I've created java.util.concurrent package in my Android project and it runs fine. – urgentx Mar 01 '18 at 03:03
  • @urgentx You mean you could call the package-private method/field and do whatever it's supposed to do, and not get an exception or error? – Jai Mar 01 '18 at 04:50
  • Nope, if I re-declare an already existing util.concurrent class it will not import it, but will still compile. If I create a class Test in java.util.concurrent and I can use it elsewhere without issue. – urgentx Mar 01 '18 at 20:51
0

You will be blocked by the class loader if the package name is prohibited, as in the case of java, or if you're trying to break into a package that is sealed in the JAR file it is distributed in.

user207421
  • 305,947
  • 44
  • 307
  • 483
-1

Java packages are backed by folders on the file system, therefore you cannot create a copy of a package as it would just be the same folder.

There is nothing stopping you from creating a java.util package in your own project and using that. It would be a unique package name, and have nothing to do with the Java API.

urgentx
  • 3,832
  • 2
  • 19
  • 30
  • He didn't say anything about classes though. I understood that the OP was more interested in taking a look at the package-visible stuff. – Andrey Tyukin Mar 01 '18 at 01:37
  • Java packages can be in jar files too so you could very well have conflicts by having different jar files with the same packages and class. – Simon Berthiaume Mar 01 '18 at 03:39
  • This is exactly what he has done, and it has failed. You cannot create classes in a `java.*` package. The JVM will not load them. – user207421 Mar 01 '18 at 04:37
  • @EJP It seems to be VM/build tool dependent, I had no issues doing that in an Android project. – urgentx Mar 01 '18 at 20:35