1

I am developing an application in Java whereby I would like to pass an object as part of an interface into other methods of classes written by other developers in the team. The object I'm passing in has setters and getters in the normal manner, but I don't want some of the classes written by others to access some of the setters of the object passed (different setters would be available to different classes when they use the object). Is this possible in Java? i.e. to define which classes may use which methods in other classes on a per-class basis?

I guess what I'd like to do is something like:

someObject.method(passInObject[but don't give access to passInObject.thisSetter])

Where 'someObject' is an object of a class written by a team member, and 'passInObject' is an object from my class but I want to protect some of the members in it from this specific someObject class.

I'm guessing not and I will need to use inheritance to override those setters I don't want specific other modules to use/see, but it seems clunky to have a new inherited class per using class based on protecting some internal values from only some using classes. I could to a check in the code that a member's value hasn't been changed but that's too late and the damage is done (undoing may be expensive). I could check the name of the class in the setter method itself and do nothing if the name is on a 'banned' list, but that seems very clunky and error prone too. What I want is the calling code to restrict which members can be called in the passed object.

Or am I missing something and there is a common pattern to deal with this?

  • 6
    You probably can with Reflection, but the fact that you need to have this sort of control is very problematic and probably indicative of severe issues in your architecture and/or design. Can you explain more the context? – Arseni Mourzenko Jan 26 '15 at 12:04
  • 1
    it's called "trust in your team mates" – ratchet freak Jan 26 '15 at 12:04
  • 1
    @ratchetfreak - even with the best team mates in the world, if something can go wrong, then it will go wrong – paul Jan 26 '15 at 12:25
  • @paul but when it does go wrong you can then shout at the guilty party. – ratchet freak Jan 26 '15 at 12:31
  • did you consider cutting down usage by something like this? `public final /*prevent override*/ WhateverReturnType thisSetter() { throw new UnsupportedOperationException(); /*prevent usage*/ }` – gnat Jan 26 '15 at 16:46

5 Answers5

9

That cannot be done. Your problems arise from violating ISP.

That said, the only idea I can think of is to force client classes to register with your classes in order to be able to call their methods or they get a NotRegisteredException. Once they register you can check their type and rise a YouAreNotAllowedToCallThisMethodException if the registered class is not in a list of allowed classes.

That's a very inelegant solution and I'd rather correct the ISP violations by segregating interfaces. But, that doesn't prevent your co-workers from using the interfaces you don't want them to use.

The following code examples are from this great answer by user Marjan Venema from another question.

interface IEverythingButTheKitchenSink
{
     void DoDishes();
     void CleanSink();
     void CutGreens();
     void GrillMeat();
}

vs

interface IClean
{
     void DoDishes();
     void CleanSink();
}

interface ICook
{
     void CutGreens();
     void GrillMeat();
}
Tulains Córdova
  • 39,201
  • 12
  • 97
  • 154
  • So are you suggesting one Interface per calling class (or different 'role' I guess?) and my called class implements all of those interfaces but some interfaces omit some of the setter methods based on role? – David Scholefield Jan 26 '15 at 13:57
  • 1
    @DavidScholefield Yes, an interface for each 'role'. Methods thar are common to several interfaces are implemented only once. – Tulains Córdova Jan 26 '15 at 14:00
  • OK I understand - there's something 'smelly' about having a class that only has some methods exposed through a role based Interface (though all methods will be exposed in total through a combination of all Interfaces) but this may just because I'm not familiar with this idea. I like it though - thanks. – David Scholefield Jan 26 '15 at 14:23
  • @DavidScholefield This great answer from another question explains the concept well with examples: http://programmers.stackexchange.com/a/202342/61852 . Just bellow that one, there'ss an answer of mine, which is not as good though. – Tulains Córdova Jan 26 '15 at 14:54
  • @DavidScholefield I improved the answer by adding the examples belonging to the answer I previously recommended to you from another question, with due credits of course. – Tulains Córdova Jan 26 '15 at 15:04
  • Yes, I appreciate that - well explained. Thanks :) – David Scholefield Jan 26 '15 at 15:27
5

Hiding inherited methods is a terrible idea and almost guaranteed to cause you grief.

I would say that this is what Interfaces are for; a "disclosure agreement" between two or more classes that accurately describes what each is allowed to know about the other[s].

Of course, this will get just a mite fiddly if its mixed with inheritance as you describe - should your base class implement the Interface or should each derived class do it for itself? YMMV.

Phill W.
  • 11,891
  • 4
  • 21
  • 36
  • I'm not sure I follow this - I thought an Interface specified what the class implementing the interface needs to provide in terms of methods, not what methods that class can or can not access. So I can't do this by expecting an external class to implement a given set of methods - or am I missing something? – David Scholefield Jan 26 '15 at 13:50
  • It cuts both ways. If a class implements an interface, then it guarantees to have implementations for the interface methods, etc. Sure. But it also allows you to use that class in a situation that demands those methods. It allows you to treat the implementing class "as a" instance of something else - any external method can demand an argument that is, say, "[i]loadable"; it doesn't matter what you pass to it as long as it is "[i]loadable" and the external method can *only* do "[i]loadable" things with the given argument (without naughty downcasting). – Phill W. Jan 27 '15 at 11:50
4

You cannot do exactly what you want - see the other answers, but there are a couple of things you could do.

  1. You could have a package private interface that exposes the setters, and a public interface that exposes the getters.
    • You mention that you want to use the setters in multiple packages in your own code. Why is this? This is a code smell for me - if your own code might mess with the internal workings of a class outside of the package where the class is defined, it sounds like you are breaking encapsulation and you should consider refactoring.
  2. You could have a builder/factory object which releases immutable snapshots of these classes.
    • This is the preferred approach, especially if your application uses multithreaded code. Creating a POJO that contains all the data (but none of the mutability) of your original class will add the safety that you desire, plus it will make the code much easier to debug later.

No matter what you do, spending some energy on limiting the situations where shared objects can mutate, especially outside the package, will both help to address this problem and make your code easier to maintain later on.


Further reading:

durron597
  • 7,590
  • 9
  • 37
  • 67
0

There are many ways to do that in Java depending on your specific scenario.

By one hand, we could start analyzing if access modifiers could help in this scenario.

For instance, in Java the package can be used to modularize your code.

package a;

public class A {
   private String foo;
   public String getFoo(){ return this.foo; }
   void setFoo(String foo){ this.foo = foo; }
}

In the code above, only classes in the package A would ever be allowed to access the method setFoo since it is defined with a package-level access but everyone could invoke getFoo() since it is public.

If you know the users of your class will be in different package (which is the most typical scenario) than this would work perfectly for you. Use the package to define your cohesive modules and expose only what you want to be exposed.

If you want to hide functionality for the members of your own package than chances are that something could be wrong with the design maybe you need a subpackage or use more interfaces as suggested in the other answer.

edalorzo
  • 2,634
  • 1
  • 19
  • 28
  • This does't really do what I want - there will be a number of other Classes in other packages (and some in the same package) and I want to be able to allow *some* of them to access some of the setters depending on which class is using the object. Your solution blocks access to all other packages which isn't the problem. It's the *selectivity* based on Class (not whether the class is in or out the current package). – David Scholefield Jan 26 '15 at 13:46
0

It is possible that your mistake is taking a too fine-grained approach to access. Are you certain that each user of your class will have different access? Perhaps your actual problem is that you should be implementing a Role mechanism where only a user with a specific role can have access to certain methods.

A Role mechanism can be implemented using different interfaces or even using a Proxy for real fine-grained control.

OldCurmudgeon
  • 778
  • 5
  • 11