6

In Java, by leaving the access modifier as the default one (blank), the fields becomes accessible to only members in the same package. However, this is not preventing others from declaring their classes in the same package and then accessing the "default" fields from there.

Is there a way in Java to make fields C# equivalent to internal. That is, when I build my library (JAR file), there's no way others can access those fields from outside the JAR? Even when declaring their classes in the same package as my classes.

Here is my declaration in my library:

package com.my.package;
class MyRestrictedClass{
}



What I'm trying to prevent is the user of my library to do from their project with my jar added to their build path something like:

package com.my.package; //Add their class to my package
public class DeveloperClass{
    public void main(){
        MyRestrictedClass foo = new MyRestrictedClass();
    }
}
AxiomaticNexus
  • 6,190
  • 3
  • 41
  • 61

2 Answers2

7

You can seal the package. That prevents people from adding classes to the classpath (though you still have to protect your jars).

http://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html

Having sealed your jar, you can still compile a class which claims to be in the same package, but when you run it, it'll fail to run:

Exception in thread "main" java.lang.SecurityException: sealing violation: can't seal package org.splore.so.access: already loaded
at java.net.URLClassLoader.getAndVerifyPackage(URLClassLoader.java:395)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:417)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.splore.so.access.AccessTestFromOtherPackage.main(AccessTestFromOtherPackage.java:5)
CPerkins
  • 8,968
  • 3
  • 34
  • 47
  • I tried that. But I can still access my "default" classes from outside the jar. I checked my manifest and it's indeed sealed. – AxiomaticNexus Nov 04 '13 at 16:56
  • Are you sure your "default" classes are properly defined? – CPerkins Nov 04 '13 at 17:28
  • I suppose: `class MyClass{}` From a project with the jar added to its build path I can still do: `MyClass myClass = new MyClass();`. Only if I declare the calling code to be in the same package of course. – AxiomaticNexus Nov 04 '13 at 17:30
  • I just saw your edit, and we are ALMOST in the same page, but not quite. I have edited my question. – AxiomaticNexus Nov 04 '13 at 17:34
  • Look at my edited question. The only difference between your example and mine is that the developer declares their class in the same package as mine. – AxiomaticNexus Nov 04 '13 at 17:42
  • They (you) should not be able to do that if all you have access is to is a sealed jar. Are you sure your environment doesn't also give you the raw classes or an unsealed jar? – CPerkins Nov 04 '13 at 18:34
  • I'm using Eclipse. All I'm doing is exporting my project to a JAR file and marking the JAR as "sealed" on one of the wizard's steps. Then I'm removing the project from my workspace, creating a new project and adding the newly generated JAR to the new project's build path. In the new project I can do what I showed on my question . Have you tried to recreate the scenario? – AxiomaticNexus Nov 04 '13 at 18:53
  • Yes. See edited reply. – CPerkins Nov 04 '13 at 20:30
  • Actually running it! Isn't that something I was supposed to do from the start? I'm so stupid! Sorry, I was just so caught up expecting it to show the error at compile time, the thought of a possible error at run time did not cross my mind. That answers the question. Thanks for your help. – AxiomaticNexus Nov 04 '13 at 20:49
-1

you might want to try other access modifiers such as "protected". However: if someone really wants to access your method, he/she could use reflections and override the modifier at runtime, making it available as they want. They could go even further and e.g. remove final-flag and so on. So it's not safe to assume that if you use proper modifiers no one will be able to access your classes.

I don't know right now, but perhaps there is an annotation, which could help the user of your library understand, that they should not use your classes (except for the public API you provide). Perhaps there is something similar to @depricated or something, but I haven't used this myself.

Igor
  • 1,582
  • 6
  • 19
  • 49
  • 1
    It would be nice if the downvoters had the patience to explain why they downvote... – Igor Nov 05 '13 at 13:50
  • 1
    Wasn't me, but my guess is that the downvote was because `protected` is actually more accessible than (default) and also that your answer doesn't really give a solution, but is rather a guess. – AxiomaticNexus Nov 05 '13 at 19:25