Java Forum / General / January 2008
How to let the methods of a class only can be invoked by a special package(the class not in the package)?
Jebel.Star@gmail.com - 22 Jan 2008 04:01 GMT There is a class A in package XX.ZZ.GG , and A has a static method A.GetInstance(). There are 3 classes B, C, D in package XX.ZZ . How can I make the A.GetInstance() only can be invoked by the B, C and D.
Roedy Green - 22 Jan 2008 04:42 GMT >How can I make the A.GetInstance() only can be invoked by the B, C and >D. There are three levels: public -- everyone, package, just in same package, and private -- just current class.
To pull off what you want means putting the classes that can talk in the same package.
see http://mindprod.com/jgloss/package.html
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Lew - 22 Jan 2008 14:50 GMT >> How can I make the A.GetInstance() only can be invoked by the B, C and >> D. > > There are three levels: public -- everyone, package, just in same > package, and private -- just current class. And protected - package-private plus inheriting classes. Don't forget.
 Signature Lew
Patricia Shanahan - 22 Jan 2008 04:51 GMT > There is a class A in package XX.ZZ.GG , and A has a static method > A.GetInstance(). There are 3 classes B, C, D in package XX.ZZ . > How can I make the A.GetInstance() only can be invoked by the B, C and > D. There are really untidy things you could do at run time to get a stack trace and check that the caller is one of the specified method.
However, it would be much better to reorganize the packaging.
Patricia
Jebel.Star@gmail.com - 22 Jan 2008 05:23 GMT > Jebel.S...@gmail.com wrote: > > There is a class A in package XX.ZZ.GG , and A has a static method [quoted text clipped - 8 lines] > > Patricia Unfortunately I have no right to reorganize the packaging, and I don't known how to get a stack in the JVM with Ver 1.3 .
Lew - 22 Jan 2008 14:53 GMT >> Jebel.S...@gmail.com wrote: >>> There is a class A in package XX.ZZ.GG , and A has a static method >>> A.GetInstance(). There are 3 classes B, C, D in package XX.ZZ . >>> How can I make the A.GetInstance() only can be invoked by the B, C and >>> D. Can you make the A.staticMethod() protected?
If so, protected access might give you partial protection - any other package can have an extending class, but they must do so in order to access the method.
<http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6> <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.2.1>
 Signature Lew
Andreas Leitgeb - 22 Jan 2008 16:03 GMT >> Jebel.S...@gmail.com wrote: >> > There is a class A in package XX.ZZ.GG , and A has a static method [quoted text clipped - 10 lines] > Unfortunately I have no right to reorganize the packaging, and I don't > known how to get a stack in the JVM with Ver 1.3 . You could throw an exception, catch it immediately, and see what you can read from the exception's printStackTrace(), by passing it your own PrintWriter (or PrintStream), wrapped around some ByteArrayOutputStream.
I just tried it with an (admittedly newer-than-1.3) java: class X { public static void main(String[] args) { foo(); } public static int foo() { try { throw new Exception("foo"); } catch (Exception e) { e.printStackTrace(System.out); } return 0; } } Try, if that also works with java-1.3, in that it also writes the "outer"-levels. To implement this in to-be- protected code, You'd of course not print to stdout, but instead to a bytearray. Happy parsing that automatically. :-)
... But then, again, it's quite an unusual wish, what you made.
Jebel.Star@gmail.com - 24 Jan 2008 03:52 GMT On Jan 23, 12:03 am, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> Jebel.S...@gmail.com <Jebel.S...@gmail.com> wrote: > >> Jebel.S...@gmail.com wrote: [quoted text clipped - 35 lines] > > ... But then, again, it's quite an unusual wish, what you made. Thanks for all of you. You let me to find the limitation of my design. So I change it.
I changed my design:
1 Add a protect method GetInstance() in Class B; 2 Add a class E which is extends from B in package XX.ZZ.GG. Create a protected method GetInstance() which has the same function of A.GetInstance() in class E. Remove the Method A.GetInstance(). 3 Add a static member 'B e ' withe the default access right in Class B, construct 'e'in the static block of B as 'E': static{ e = new E; }
In this design B,C and D can invoke B.e.GetInstance() which is E.GetInstance(), any other classes that is not in package XX.ZZ (and also not in package XX.ZZ.GG) can't invoke the E.GetInstance().
Is my design OK ?
Andreas Leitgeb - 24 Jan 2008 12:05 GMT > 1 Add a protect method GetInstance() in Class B; > 2 Add a class E which is extends from B in package XX.ZZ.GG. Create a [quoted text clipped - 3 lines] > B, construct 'e'in the static block of B as 'E': > static{ e = new E; } I'm not sure if I remember all involved classes correctly: xx.zz.gg.B is the one you want only accessible from classes in package xx.zz, which is principially not possible to guarantee from JLS point fo view.
So, you create a class xx.zz.E which derives from B, and thus has also available all of B's protected functionality.
However, anyone else could create yet another derivative of B, as hostile.mypackage.MyE, using the same mechanism as your E does, to still access xx.zz.gg.B
> Is my design OK ? It's quite complicated for hardly any gain.
Java's protection scheme *cannot* discriminate between two packages, when both are different from the current one. Whatever you can do from classes of package xx.zz to access classes in xx.zz.gg, you can always do the same from any unrelated package aa.bb.cc, as well.
There are exactly these possibilities: - use reflection or exception-stacktraces at runtime to determine calling class (quite complicated, if you're stuck in 1.3, and still some overhead even with 1.4's new methods for easier stack-inspection. - put all the relevant classes in one package. Or add a class C to package xx.zz.gg that will wrap B's methods such, that no misuse can occur when calling through C. Then you can give all B's methods default-access.
Maybe we can help more, if you tell us, who/what exactly you want to protect your class B from. E.g. against crackers? Against accidental inappropriate use from other parts of your own project?
Andreas Leitgeb - 24 Jan 2008 14:01 GMT > There are exactly these possibilities: > - use reflection or exception-stacktraces at runtime to > determine calling class (quite complicated, if you're > stuck in 1.3, and still some overhead even with 1.4's > new methods for easier stack-inspection. Based on Thomas Schodt's posting, the SecurityManager appears to make a nicer variant of this strategy, but is still only doing runtime-checking.
> - put all the relevant classes in one package. Or add a > class C to package xx.zz.gg that will wrap B's methods > such, that no misuse can occur when calling through C. > Then you can give all B's methods default-access. That would allow compiletime checking.
Jebel - 25 Jan 2008 04:24 GMT > > - use reflection or exception-stacktraces at runtime to > > determine calling class (quite complicated, if you're [quoted text clipped - 4 lines] > to make a nicer variant of this strategy, but is still only > doing runtime-checking. I think homas Schodt's design is much better than mine, simple and effective. But I want to know that if I invoke A.GetInstance() very frequently, id the SecurityManager .getClassContext() going to take much time? -------------------------------------------------------------------------------------------------
> > - put all the relevant classes in one package. Or add a > > class C to package xx.zz.gg that will wrap B's methods > > such, that no misuse can occur when calling through C. > > Then you can give all B's methods default-access. > > That would allow compiletime checking. I not understand how to do this. How can I "wrap" B's methods ? Would you please provide some code as a example?
Thanks a lot. Jebel
Andreas Leitgeb - 25 Jan 2008 11:58 GMT > I not understand how to do this. How can I "wrap" B's methods ? > Would you please provide some code as a example? It was based on a wrong understanding on my side. Sorry, but I think it doesn't apply, anyway.
The point was about your class in xx.zz.gg which you could give a such limited interface, that noone could do anything harmful with it, even if the wrong "user" tries...
The wrapping was just meant as a way to restrict the interface: e.g.: package xx.zz.gg; class B { // lots of public methods, some of which are potentially dangerous public void foo() { ... } public void bar() { ... } public void snafu() { ... } ... } and: package xx.zz.gg; class BWrapper { B wrappedB; BWrapper(B b) { wrappedB=b; } private B getB() { return wrappedB; } // just the really important methods: public void foo() { do some checks, and then: getB().foo(); } } After that, you can give all the methods of B default-access, and no one else can use anything than foo() on B, and only through your class BWrapper (unless they find a way to sneak code into xx.zz or xx.zz.gg bypassing your classloader, or patching their JVM).
Also, I don't yet understand what big evil would be unleashed by letting people just use your xx.zz.gg.B as they feel like.
Jebel - 26 Jan 2008 05:22 GMT On Jan 25, 7:58 pm, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> > I not understand how to do this. How can I "wrap" B's methods ? > > Would you please provide some code as a example? [quoted text clipped - 33 lines] > Also, I don't yet understand what big evil would be unleashed by > letting people just use your xx.zz.gg.B as they feel like. Thank you Andreas.You have teach me much, and now I understand what is the ' wrap ' . :-) Thank you very much.
Jebel - 24 Jan 2008 14:41 GMT > I'm not sure if I remember all involved classes correctly: > xx.zz.gg.B is the one you want only accessible from [quoted text clipped - 33 lines] > E.g. against crackers? Against accidental inappropriate use > from other parts of your own project? There is some thing that I didn't say clearly. I am designing a platform and use some source(the package xx.zz) of another company, so I can't move my source(the package xx.zz.gg) into the package xx.zz. I can prevent the applications that use my source as platform to create the package xx.zz from the classloader( the applications must use the classloader that offered from me). And the class B will know what is the name of my package and class. So I think applications can't overrides my class E. I want to prevent that if My design is betrayed, the applications also can't disturb the behavior of package xx.zz.
And I am not very understand how to do this:
> - put all the relevant classes in one package. Or add a > class C to package xx.zz.gg that will wrap B's methods > such, that no misuse can occur when calling through C. > Then you can give all B's methods default-access. Thank you very much. Jebel
Roedy Green - 24 Jan 2008 08:57 GMT >There is a class A in package XX.ZZ.GG , and A has a static method >A.GetInstance(). There are 3 classes B, C, D in package XX.ZZ . >How can I make the A.GetInstance() only can be invoked by the B, C and >D. Please follow the caps conventions. See http://mindprod.com/jgloss/codingconventions.html
Your question translated then becomes:
>There is a class A in package xx.zz.gg, and A has a static method >A.getInstance(). There are 3 classes B, C, D in package xx.zz . >How can I make A.getInstance()so that it can only be invoked from >classes B, C and D. You can't. To do that classes A, B, C and D would have to be in the same package, and getInstance would need default package scope. You could still invoke it from class A.
Note that, as far as Java is concerned, package xx.zz.gg and package xx.zz are TOTALLY unrelated.
see http://mindprod.com/jgloss/package.html
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Jebel - 24 Jan 2008 09:54 GMT On Jan 24, 4:57 pm, Roedy Green <see_webs...@mindprod.com.invalid> wrote:
> On Mon, 21 Jan 2008 20:01:50 -0800 (PST), Jebel.S...@gmail.com wrote, > quoted or indirectly quoted someone who said : [quoted text clipped - 24 lines] > Roedy Green, Canadian Mind Products > The Java Glossary,http://mindprod.com I know that "package xx.zz.gg and package xx.zz are TOTALLY unrelated ".The names of the two packages are no meaning for my problem.
The classes A and E are in the package XX.ZZ.GG; and the classes B, C and D are in the package XX.ZZ. The class E extends from class B.
When the class C wants to invoke the E.GetInstance()(has the same function of the previous A.GetInstance) it invokes B.e.GetInstance().
package XX.ZZ; import XX.ZZ.GG.A; public class C { public void Func() { ... ... A a = B.e.GetInstanc(); ... ...
}
}
The 'e' is a static member of class B, and 'e' is declared as B but construct as E:
package XX.ZZ; import XX.ZZ.GG.E; import XX.ZZ.GG.A; public class B { static B e;
static{ e = new E; } protect A GetInstance(){ return null;}
... ... }
And the class E and class A are in the same package, E can do some thing in its method GetInstance with A. package XX.ZZ.GG; import XX.ZZ.B; final public class C extends B { private static A onlyOne; protect A GetInstance() { if(onlyOne == NULL){ onlyOne = new A;} return onlyOne; } }
Class A : package XX.ZZ.GG; public class A { // the access right of constructer of A is default( the class in the same package can access) A(){... ...}
... ... }
That is all.
Roedy Green - 24 Jan 2008 11:24 GMT > package XX.ZZ; please don't do that. see http://mindprod.com/jgloss/codingconventions.html
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Lew - 24 Jan 2008 14:34 GMT >> package XX.ZZ; > > please don't do that. see > http://mindprod.com/jgloss/codingconventions.html Please note that ignoring good advice, especially from one such as Roedy who really goes out of his way to be helpful, is risky. You send a message that you aren't really interested in good advice, thus lowering the expected value of advice that you will receive. Quoting that advice, then disregarding, gives the no doubt accidental impression that you are evincing deliberate disrespect. I'm sure that you did not mean that, of course.
There's good reason for the coding conventions, particular where upper- and lower-case names are concerned. These conventions facilitate discourse about Java programs. Discourse about Java programs is the whole point of the clj.programmer newsgroup. There is a tolerance for variation from some parts of the convention, formalized in 1999, but only to a point. Indentation, for example, has two major variants with permissible indentation sizes that can vary in a narrow range. However, the case conventions are pretty solid and should not be ignored.
Java from the beginning has been a "literate programming" language - information about the program is embedded in the source code for the program. Javadocs are one aspect of that. Annotations are another. The naming conventions stress the use of names out of the domain of discourse - the logical model for the program, not out of the implementation. Thus "WidgetExtractor" tells us by the initial upper-case letter that this is a class name for something that models a widget extractor. No need to embed the redundant "Class" in a name like "WidgetExtractorClass". The identifier "widgetExtractor" in this context now tells us that we see an instance of that class. "widgetExtractor()" jars the senses, because it's a noun phrase for a method name; "widgetExtract()" would be more comfortable. With little if any cognitive strain one can infer many things about the logic and the domain model from a source code artifact without interrupting the flow of reviewing it, if these conventions are rigorously followed.
So please, for both engineering and social reasons, use lower-case identifiers for your package names.
 Signature Lew
Thomas Schodt - 24 Jan 2008 13:47 GMT > There is a class A in package xx.zz.gg , and A has a static method > A.getInstance(). There are 3 classes B, C, D in package xx.zz > How can I make the A.getInstance() only can be invoked by the B, C and D class A { private A() {}; private static final Set allowed = new HashSet() {{ add("xx.zz.B"); add("xx.zz.C"); add("xx.zz.D"); }}; static A a = null; static A getInstance() { Class[] ca = new SecurityManager() { protected Class[] getClassContext() { return super.getClassContext(); } }.getClassContext(); // ca[0] is the anonymous security manager // ca[1] is this class ("A") // ca[2] is the calling class if (!allowed.contains(ca[2].getName())) { throw new InstantiationError("Not allowed from "+ca[2]); } if (a==null) { a = new A(); } return a; } }
Lew - 24 Jan 2008 14:46 GMT >> There is a class A in package xx.zz.gg , and A has a static method >> A.getInstance(). There are 3 classes B, C, D in package xx.zz [quoted text clipped - 24 lines] > } > } That's a great pattern. Take it a step further and store a Map <String, Class <? extends Allowed>> or a Map <AllowedEnum, Class <? extends Allowed>> where 'Allowed' is a supertype for the classes that are allowed. The 'String' or 'AllowedEnum' enum identify the particular implementing class for each case you want to permit.
For that matter, you could craft an 'AllowedEnum' where each enum instance's behavior does what you want - that could well be your optimal solution in that it gives you compile-time safety on the behaviors, not merely run-time checks. From a maintenance standpoint, such an enum collects verification of an action's legality and its activity into a single class, binding them at compile time, making life easier.
The downside to the enum implementation is that you have to recompile the world to extend the behaviors. If runtime configurability is what you need, then you need a runtime technique such as the ServiceProvider pattern.
 Signature Lew
Roedy Green - 24 Jan 2008 20:59 GMT On Thu, 24 Jan 2008 13:47:14 +0000, Thomas Schodt <spamtrap0607@xenoc.demon.co.uk> wrote, quoted or indirectly quoted someone who said :
It seems to me you would have to make getClassContext public. Is it accessible just as protected? The original was already protected.
// Determining the calling class. // ca[0] is the anonymous security manager // ca[1] is this class // ca[2] is the calling class Class[] ca = new SecurityManager() { // convert from protected to public to make the method accessible. public Class[] getClassContext() { return super.getClassContext(); } }.getClassContext();
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Jebel - 26 Jan 2008 05:09 GMT On Jan 25, 4:59 am, Roedy Green <see_webs...@mindprod.com.invalid> wrote:
> On Thu, 24 Jan 2008 13:47:14 +0000, Thomas Schodt > <spamtrap0...@xenoc.demon.co.uk> wrote, quoted or indirectly quoted [quoted text clipped - 19 lines] > Roedy Green, Canadian Mind Products > The Java Glossary,http://mindprod.com No, it's needn't. A class can invoke the methods with protected-access of the inner classes.
Stefan Ram - 24 Jan 2008 15:24 GMT >How can I make the A.GetInstance() only can be invoked by the B Any static measure is insufficient, because new classes can be generated and loaded at run-time. Such classes would not have been inspected by a static measure.
Therefore, the measure must be dynamic. The answers I am aware of have implied that »A.GetInstance()« will somehow check its caller. Such answers do not actually address how to /prevent/ the invocation, because at the time when »A.GetInstance()« checks its caller it already /has been/ invoked, so it is too late to prevent it. The question was to prevent this, not to detect and report it, once it has happend.
Therefore, it might not be possible to do this at all.
One could use a patched JVM to do this.
However, there might be multiple »B« classes (one for each class loader). One also needs to specify which of them should be allowed to call »A.GetInstance()«. For this, one needs to identify the class loaders involved.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|