java - public interface - private menthods

G

Gianni Mariani

.... warning - I'm more familiar with C++ but I'm learning Java for new
project. I'll try hard not to troll. ...

Say I have a class that exposes some interfaces. The intent is that
methods may be overridden by clients but only the class that defines the
interfaces are allowed to call them.

In C++ you would do it like so:

class X
{
public:
class Y
{
friend class X;
private:
virtual void = 0;
};

void YConsumer( Y & y )
{
y.FuncOnlyForX();
}
};

class YClient : public X::Y
{
public:
void FuncOnlyForX() // override X::Y
{
std::cout << "THIS IS YClient\n";
}
};

int main()
{
X x;
X::Y & y = YClient();

y.FuncOnlyForX(); // error

x.YConsumer( y ); // OK
}

I tried this in Java but the compiler keeps on getting in the way:

public class X
{
public interface Y
{
private void FuncOnlyForX(); // javac saya illegal use of private
}

public void YConsumer( Y y )
{
y.FuncOnlyForX();
}
}

public class Yclient extends X.Y
{
void FuncOnlyForX()
{
}
}

So, how do you get java to enforce use visibility policy on interfaces ?
 
J

Joshua Cranmer

Gianni said:
So, how do you get java to enforce use visibility policy on interfaces ?

You don't. The JLS clearly defines that all members of the interface are
public; the `public' keyword itself is optional.

It looks like an abstract class would be better here, but a subclass
cannot override a private function, so your function would need to be
protected or package-protected.
 
D

Daniel Pitts

Gianni said:
.... warning - I'm more familiar with C++ but I'm learning Java for new
project. I'll try hard not to troll. ...

Say I have a class that exposes some interfaces. The intent is that
methods may be overridden by clients but only the class that defines the
interfaces are allowed to call them.
[snip c++ example]
So, how do you get java to enforce use visibility policy on interfaces ?

Try using Composition instead of Inheritance.

Also note, you shouldn't call virtual methods (all non-final or
non-private methods in Java) from constructors.

Alternatively, if it really makes sense to have inheritance in your
case, use protected abstract methods rather than using an interface.
 
S

Stefan Ram

Gianni Mariani said:
Say I have a class that exposes some interfaces. The intent is that
methods may be overridden by clients but only the class that defines the
interfaces are allowed to call them. [...]
So, how do you get java to enforce use visibility policy on interfaces ?

In Java, interfaces are »declared«, which usually happens
outside of a class.

Most Java programmers do not write in C++ first and translate
to Java. They immediatly rush to code in Java and rarely miss
the friend keyword (yes, it sometimes happens).

To allow only certain other entities to call a method,

- you can either make it public and accept that violations
of the rule will not be enforced by the compiler.
You might use an additional style-checker instead, Or,

- you can use annotations and JSR 269 and to extend the
compilation process so as to enforce your rules. Or,

- you can pass a token object (at run-time) to all
objects that are intended to be your »friends«.
This token then will be needed to do a specific call.

The token might be the target object itself. Its class
might use a private constructor, so that not everyone
can create instances. Then, it will create an object »a«
internally using the private constructor and pass a
reference to »a« to every other object »o« that should be
allowed to call methods of »a«. Now, every of the objects
»o« can call »a«, because it holds a reference to it,
but one else can, because the constructor is private and
he does not has a reference.
 
S

Stefan Ram

To allow only certain other entities to call a method,

Of course, the most common approach in Java is to put all
classes that should be allowed to call each other in a single
package and use default or protected access.
 
G

Gianni Mariani

Stefan said:
Most Java programmers do not write in C++ first and translate
to Java. They immediatly rush to code in Java and rarely miss
the friend keyword (yes, it sometimes happens).

I'm just using the C++ as an example - it's a pattern I've used alot to
avoid mis-use of an API in C++.
To allow only certain other entities to call a method,

- you can either make it public and accept that violations
of the rule will not be enforced by the compiler.
You might use an additional style-checker instead, Or,

Sure, but that specifically what I want to avoid. One of the things
I've learned in writing C++ is to make the compiler catch as many
violations at compile time as possible. That way you avoid more costly
debugging time.
- you can use annotations and JSR 269 and to extend the
compilation process so as to enforce your rules. Or,

I'm only just getting to understand annotations. Any pointers on that
you can share for this specific issue ?
- you can pass a token object (at run-time) to all
objects that are intended to be your »friends«.
This token then will be needed to do a specific call.

It really has to be a compile time check. Mostly a waste of time otherwise.

Thanks for the help.
G
 
S

Stefan Ram

Gianni Mariani said:
I'm only just getting to understand annotations. Any pointers on that
you can share for this specific issue ?

If you use

public @Friend(classA,classB,methodA,methodB) int x;

Java would normally allow »x« to be accessed from everywhere.

JSR 269 allows custom annotation processing during compile time.

So, if all source files of the project are being compiled
anew, you could add a check to inspect code accessing »x«
and raise an error if it is not part of the friend list.

I have not tried this, so I am not sure whether it can
be done.

(But, once you have build a JAR-library it might be difficult
again to enforce that third-party code does not access »x«.)

For an example of a Java extension via JSR 269 see:

http://www.hanhuy.com/pfn/java_property_annotation

For more on JSR 269:

»Let us discuss the core points in writing a
Custom Annotation Processor in Java«

http://www.javabeat.net/javabeat/java6/articles/2007/06/java-6-0-new-features-part-2/

»Writing your first (Hello World) Annotation Processor

Annotation processing is a form of meta-programming. «

http://blogs.sun.com/prats/entry/javac_demo@foss-2006

»Annotation processing is now enabled by default in javac«

http://blogs.sun.com/darcy/?page=2

»In the following example, we implement a checker for
empty catch blocks (because "eating exceptions silently"
is considered bad) and warn the user.«

http://blogs.sun.com/sundararajan/date/200611

»So how can I reliably find all unchecked exceptions? Very
easily if I use an annotation processor.«

http://blogs.sun.com/ahe/entry/throwing_unchecked_exceptions

You can find the documentation of Java SE classes at

http://download.java.net/jdk7/docs/api/allclasses-frame.html
 
S

Steven Simpson

Gianni Mariani wrote:

[C++]
class X
{
public:
class Y
{
friend class X;
private:
virtual void = 0;
};
Okay, the (omitted) method is effectively public to X because of the
friendship, which Java doesn't have an equivalent of.

[Java:]
public class X
{
public interface Y
(Doesn't the lack of 'static' place additional restrictions on Yclient
implementing it? Also, it should be 'static' to correspond to the C++
version anyway.)
{
private void FuncOnlyForX(); // javac saya illegal use of private
}

public void YConsumer( Y y )
{
y.FuncOnlyForX();
}
}

public class Yclient extends X.Y ('implements'?)
{
void FuncOnlyForX()
{
}
}

So, how do you get java to enforce use visibility policy on interfaces ?

In the above code, you're forced to expose Yclient's 'private' method
because it implements X.Y directly. Instead, get your Yclient to
instantiate an inner X.Y, and pass it to the right X:

public class X {
public static interface Y {
void funcOnlyForX();
}

public void yConsumer(Y y) {
y.funcOnlyForX();
}
}

public class YClient {
private void privateFuncOnlyForX() { ... }
public void sendToX(X x) {
x.yConsumer(new X.Y() {
public void funcOnlyForX() { privateFuncOnlyForX(); }
});
}
}

Does that handle your case?
 
G

Gianni Mariani

Steven Simpson wrote:
....
(Doesn't the lack of 'static' place additional restrictions on Yclient
implementing it? Also, it should be 'static' to correspond to the C++
version anyway.)

Yes. I see static is just as overloaded in Java as it is in C++.

....
Does that handle your case?

.... still, anyone can call sendToX right ?
 
S

Steven Simpson

Gianni said:
Yes. I see static is just as overloaded in Java as it is in C++.

On the contrary. It really has only one meaning in Java - the member
(method, field, class, whatever) can be referred to without a containing
instance.
 
S

Steven Simpson

Gianni said:
.... still, anyone can call sendToX right ?

Yes, but they can only pass an X. Of course, they could derive from X,
and override yConsumer, which you could avoid by making either final.
But then X might be the root of a suite of classes which YClient is
meant to handle.

You could twist yourself in knots trying to solve this, but I don't
usually find it a problem, and don't worry about it particularly. The
most I'd normally do is have a YClient method to export an anonymous
inner Y, and make sure externally that it went to the right place.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top