I would like to be able to write a Java class in one package which can access non-public methods of a class in another package without having to make it a subclass of the other class. Is this possible?
Here is a small trick that I use in JAVA to replicate C++ friend mechanism.
Lets say I have a class Romeo and another class Juliet. They are in different packages (family) for hatred reasons.
Romeo wants to cuddle Juliet and Juliet wants to only let Romeo cuddle her.
In C++, Juliet would declare Romeo as a (lover) friend but there are no such things in java.
Here are the classes and the trick :
Ladies first :
package capulet;
import montague.Romeo;
public class Juliet {
public static void cuddle(Romeo.Love love) {
Objects.requireNonNull(love);
System.out.println("O Romeo, Romeo, wherefore art thou Romeo?");
}
}
So the method Juliet.cuddle is public but you need a Romeo.Love to call it. It uses this Romeo.Love as a "signature security" to ensure that only Romeo can call this method and checks that the love is real so that the runtime will throw a NullPointerException if it is null.
Now boys :
package montague;
import capulet.Juliet;
public class Romeo {
public static final class Love { private Love() {} }
private static final Love love = new Love();
public static void cuddleJuliet() {
Juliet.cuddle(love);
}
}
The class Romeo.Love is public, but its constructor is private. Therefore anyone can see it, but only Romeo can construct it. I use a static reference so the Romeo.Love that is never used is only constructed once and does not impact optimization.
Therefore, Romeo can cuddle Juliet and only he can because only he can construct and access a Romeo.Love instance, which is required by Juliet to cuddle her (or else she'll slap you with a NullPointerException).
The designers of Java explicitly rejected the idea of friend as it works in C++. You put your "friends" in the same package. Private, protected, and packaged security is enforced as part of the language design.
James Gosling wanted Java to be C++ without the mistakes. I believe he felt that friend was a mistake because it violates OOP principles. Packages provide a reasonable way to organize components without being too purist about OOP.
NR pointed out that you could cheat using reflection, but even that only works if you aren't using the SecurityManager. If you turn on Java standard security, you won't be able to cheat with reflection unless you write security policy to specifically allow it.
The 'friend' concept is useful in Java, for example, to separate an API from its implementation. It is common for implementation classes to need access to API class internals but these should not be exposed to API clients. This can be achieved using the 'Friend Accessor' pattern as detailed below:
The class exposed through the API:
package api;
public final class Exposed {
static {
// Declare classes in the implementation package as 'friends'
Accessor.setInstance(new AccessorImpl());
}
// Only accessible by 'friend' classes.
Exposed() {
}
// Only accessible by 'friend' classes.
void sayHello() {
System.out.println("Hello");
}
static final class AccessorImpl extends Accessor {
protected Exposed createExposed() {
return new Exposed();
}
protected void sayHello(Exposed exposed) {
exposed.sayHello();
}
}
}
The class providing the 'friend' functionality:
package impl;
public abstract class Accessor {
private static Accessor instance;
static Accessor getInstance() {
Accessor a = instance;
if (a != null) {
return a;
}
return createInstance();
}
private static Accessor createInstance() {
try {
Class.forName(Exposed.class.getName(), true,
Exposed.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
return instance;
}
public static void setInstance(Accessor accessor) {
if (instance != null) {
throw new IllegalStateException(
"Accessor instance already set");
}
instance = accessor;
}
protected abstract Exposed createExposed();
protected abstract void sayHello(Exposed exposed);
}
Example access from a class in the 'friend' implementation package:
package impl;
public final class FriendlyAccessExample {
public static void main(String[] args) {
Accessor accessor = Accessor.getInstance();
Exposed exposed = accessor.createExposed();
accessor.sayHello(exposed);
}
}
There are two solutions to your question that don't involve keeping all classes in the same package.
The first is to use the Friend Accessor/Friend Package pattern described in (Practical API Design, Tulach 2008).
The second is to use OSGi. There is an article here explaining how OSGi accomplishes this.
Related Questions: 1, 2, and 3.
As far as I know, it is not possible.
Maybe, You could give us some more details about Your design. Questions like these are likely the result of design flaws.
Just consider
Why are those classes in different packages, if they are so closely related?
Has A to access private members of B or should the operation be moved to class B and triggered by A?
Is this really calling or is event-handling better?
eirikma's answer is easy and excellent. I might add one more thing: instead of having a publicly accessible method, getFriend() to get a friend which cannot be used, you could go one step further and disallow getting the friend without a token: getFriend(Service.FriendToken). This FriendToken would be an inner public class with a private constructor, so that only Service could instantiate one.
Here's a clear use-case example with a reusable Friend class. The benefit of this mechanism is simplicity of use. Maybe good for giving unit test classes more access than the rest of the application.
To begin, here is an example of how to use the Friend class.
public class Owner {
private final String member = "value";
public String getMember(final Friend friend) {
// Make sure only a friend is accepted.
friend.is(Other.class);
return member;
}
}
Then in another package you can do this:
public class Other {
private final Friend friend = new Friend(this);
public void test() {
String s = new Owner().getMember(friend);
System.out.println(s);
}
}
The Friend class is as follows.
public final class Friend {
private final Class as;
public Friend(final Object is) {
as = is.getClass();
}
public void is(final Class c) {
if (c == as)
return;
throw new ClassCastException(String.format("%s is not an expected friend.", as.getName()));
}
public void is(final Class... classes) {
for (final Class c : classes)
if (c == as)
return;
is((Class)null);
}
}
However, the problem is that it can be abused like so:
public class Abuser {
public void doBadThings() {
Friend badFriend = new Friend(new Other());
String s = new Owner().getMember(badFriend);
System.out.println(s);
}
}
Now, it may be true that the Other class doesn't have any public constructors, therefore making the above Abuser code impossible. However, if your class does have a public constructor then it is probably advisable to duplicate the Friend class as an inner class. Take this Other2 class as an example:
public class Other2 {
private final Friend friend = new Friend();
public final class Friend {
private Friend() {}
public void check() {}
}
public void test() {
String s = new Owner2().getMember(friend);
System.out.println(s);
}
}
And then the Owner2 class would be like this:
public class Owner2 {
private final String member = "value";
public String getMember(final Other2.Friend friend) {
friend.check();
return member;
}
}
Notice that the Other2.Friend class has a private constructor, thus making this a much more secure way of doing it.
The provided solution was perhaps not the simplest. Another approach is based on the same idea as in C++: private members are not accessible outside the package/private scope, except for a specific class that the owner makes a friend of itself.
The class that needs friend access to a member should create a inner public abstract "friend class" that the class owning the hidden properties can export access to, by returning a subclass that implement the access-implementing methods. The "API" method of the friend class can be private so it is not accessible outside the class that needs friend access. Its only statement is a call to an abstract protected member that the exporting class implements.
Here's the code:
First the test that verifies that this actually works:
package application;
import application.entity.Entity;
import application.service.Service;
import junit.framework.TestCase;
public class EntityFriendTest extends TestCase {
public void testFriendsAreOkay() {
Entity entity = new Entity();
Service service = new Service();
assertNull("entity should not be processed yet", entity.getPublicData());
service.processEntity(entity);
assertNotNull("entity should be processed now", entity.getPublicData());
}
}
Then the Service that needs friend access to a package private member of Entity:
package application.service;
import application.entity.Entity;
public class Service {
public void processEntity(Entity entity) {
String value = entity.getFriend().getEntityPackagePrivateData();
entity.setPublicData(value);
}
/**
* Class that Entity explicitly can expose private aspects to subclasses of.
* Public, so the class itself is visible in Entity's package.
*/
public static abstract class EntityFriend {
/**
* Access method: private not visible (a.k.a 'friendly') outside enclosing class.
*/
private String getEntityPackagePrivateData() {
return getEntityPackagePrivateDataImpl();
}
/** contribute access to private member by implementing this */
protected abstract String getEntityPackagePrivateDataImpl();
}
}
Finally: the Entity class that provides friendly access to a package private member only to the class application.service.Service.
package application.entity;
import application.service.Service;
public class Entity {
private String publicData;
private String packagePrivateData = "secret";
public String getPublicData() {
return publicData;
}
public void setPublicData(String publicData) {
this.publicData = publicData;
}
String getPackagePrivateData() {
return packagePrivateData;
}
/** provide access to proteced method for Service'e helper class */
public Service.EntityFriend getFriend() {
return new Service.EntityFriend() {
protected String getEntityPackagePrivateDataImpl() {
return getPackagePrivateData();
}
};
}
}
Okay, I must admit it is a bit longer than "friend service::Service;" but it might be possible to shorten it while retaining compile-time checking by using annotations.
In Java it is possible to have a "package-related friendness".
This can be userful for unit testing.
If you do not specify private/public/protected in front of a method, it will be "friend in the package".
A class in the same package will be able to access it, but it will be private outside the class.
This rule is not always known, and it is a good approximation of a C++ "friend" keyword.
I find it a good replacement.
I think that friend classes in C++ are like inner-class concept in Java. Using inner-classes
you can actually define an enclosing class and an enclosed one. Enclosed class has full access to the public and private members of it's enclosing class.
see the following link:
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Not using a keyword or so.
You could "cheat" using reflection etc., but I wouldn't recommend "cheating".
I think, the approach of using the friend accessor pattern is way too complicated. I had to face the same problem and I solved using the good, old copy constructor, known from C++, in Java:
public class ProtectedContainer {
protected String iwantAccess;
protected ProtectedContainer() {
super();
iwantAccess = "Default string";
}
protected ProtectedContainer(ProtectedContainer other) {
super();
this.iwantAccess = other.iwantAccess;
}
public int calcSquare(int x) {
iwantAccess = "calculated square";
return x * x;
}
}
In your application you could write the following code:
public class MyApp {
private static class ProtectedAccessor extends ProtectedContainer {
protected ProtectedAccessor() {
super();
}
protected PrivateAccessor(ProtectedContainer prot) {
super(prot);
}
public String exposeProtected() {
return iwantAccess;
}
}
}
The advantage of this method is that only your application has access to the protected data. It's not exactly a substitution of the friend keyword. But I think it's quite suitable when you write custom libraries and you need to access protected data.
Whenever you have to deal with instances of ProtectedContainer you can wrap your ProtectedAccessor around it and you gain access.
It also works with protected methods. You define them protected in your API. Later in your application you write a private wrapper class and expose the protected method as public. That's it.
If you want to access protected methods you could create a subclass of the class you want to use that exposes the methods you want to use as public (or internal to the namespace to be safer), and have an instance of that class in your class (use it as a proxy).
As far as private methods are concerned (I think) you are out of luck.
I agree that in most cases the friend keyword is unnecessary.
Package-private (aka. default) is sufficient in most cases where you have a group of heavily intertwined classes
For debug classes that want access to internals, I usually make the method private and access it via reflection. Speed usually isn't important here
Sometimes, you implement a method that is a "hack" or otherwise which is subject to change. I make it public, but use #Deprecated to indicate that you shouldn't rely on this method existing.
And finally, if it really is necessary, there is the friend accessor pattern mentioned in the other answers.
A method I've found for solving this problem is to create an accessor object, like so:
class Foo {
private String locked;
/* Anyone can get locked. */
public String getLocked() { return locked; }
/* This is the accessor. Anyone with a reference to this has special access. */
public class FooAccessor {
private FooAccessor (){};
public void setLocked(String locked) { Foo.this.locked = locked; }
}
private FooAccessor accessor;
/** You get an accessor by calling this method. This method can only
* be called once, so calling is like claiming ownership of the accessor. */
public FooAccessor getAccessor() {
if (accessor != null)
throw new IllegalStateException("Cannot return accessor more than once!");
return accessor = new FooAccessor();
}
}
The first code to call getAccessor() "claims ownership" of the accessor. Usually, this is code that creates the object.
Foo bar = new Foo(); //This object is safe to share.
FooAccessor barAccessor = bar.getAccessor(); //This one is not.
This also has an advantage over C++'s friend mechanism, because it allows you to limit access on a per-instance level, as opposed to a per-class level. By controlling the accessor reference, you control access to the object. You can also create multiple accessors, and give different access to each, which allows fine-grained control over what code can access what:
class Foo {
private String secret;
private String locked;
/* Anyone can get locked. */
public String getLocked() { return locked; }
/* Normal accessor. Can write to locked, but not read secret. */
public class FooAccessor {
private FooAccessor (){};
public void setLocked(String locked) { Foo.this.locked = locked; }
}
private FooAccessor accessor;
public FooAccessor getAccessor() {
if (accessor != null)
throw new IllegalStateException("Cannot return accessor more than once!");
return accessor = new FooAccessor();
}
/* Super accessor. Allows access to secret. */
public class FooSuperAccessor {
private FooSuperAccessor (){};
public String getSecret() { return Foo.this.secret; }
}
private FooSuperAccessor superAccessor;
public FooSuperAccessor getAccessor() {
if (superAccessor != null)
throw new IllegalStateException("Cannot return accessor more than once!");
return superAccessor = new FooSuperAccessor();
}
}
Finally, if you'd like things to be a bit more organized, you can create a reference object, which holds everything together. This allows you to claim all accessors with one method call, as well as keep them together with their linked instance. Once you have the reference, you can pass the accessors out to the code that needs it:
class Foo {
private String secret;
private String locked;
public String getLocked() { return locked; }
public class FooAccessor {
private FooAccessor (){};
public void setLocked(String locked) { Foo.this.locked = locked; }
}
public class FooSuperAccessor {
private FooSuperAccessor (){};
public String getSecret() { return Foo.this.secret; }
}
public class FooReference {
public final Foo foo;
public final FooAccessor accessor;
public final FooSuperAccessor superAccessor;
private FooReference() {
this.foo = Foo.this;
this.accessor = new FooAccessor();
this.superAccessor = new FooSuperAccessor();
}
}
private FooReference reference;
/* Beware, anyone with this object has *all* the accessors! */
public FooReference getReference() {
if (reference != null)
throw new IllegalStateException("Cannot return reference more than once!");
return reference = new FooReference();
}
}
After much head-banging (not the good kind), this was my final solution, and I very much like it. It is flexible, simple to use, and allows very good control over class access. (The with reference only access is very useful.) If you use protected instead of private for the accessors/references, sub-classes of Foo can even return extended references from getReference. It also doesn't require any reflection, so it can be used in any environment.
I prefer delegation or composition or factory class (depending upon the issue that results in this problem) to avoid making it a public class.
If it is a "interface/implementation classes in different packages" problem, then I would use a public factory class that would in the same package as the impl package and prevent the exposure of the impl class.
If it is a "I hate to make this class/method public just to provide this functionality for some other class in a different package" problem, then I would use a public delegate class in the same package and expose only that part of the functionality needed by the "outsider" class.
Some of these decisions are driven by the target server classloading architecture (OSGi bundle, WAR/EAR, etc.), deployment and package naming conventions. For example, the above proposed solution, 'Friend Accessor' pattern is clever for normal java applications. I wonder if it gets tricky to implement it in OSGi due to the difference in classloading style.
I once saw a reflection based solution that did "friend checking" at runtime using reflection and checking the call stack to see if the class calling the method was permitted to do so. Being a runtime check, it has the obvious drawback.
As of Java 9, modules can be used to make this a non-issue in many cases.
Related
I facing a real hard problem in my code snippet.
I want to learn how to use Interface in Java the correct way.
So for this I have my Application-Class...
package inversionUsage;
public class Application {
public static void main(String [] args) {
String standard = "Standard version!";
if (FeatureDecisions.checkEnabledFeatures("new-feature1")) {
System.out.println("Implement new feature...");
}else {
System.out.println(standard);
}
}
}
Then I made a Interface...
package inversionUsage;
public interface AppConfiguration {
boolean isEnabled(String searchFeature);
}
I want to use the Interface in another class:
package inversionUsage;
import java.util.Arrays;
public class FeatureDecisions implements AppConfiguration{
public String [] enabledFeatures;
public String [] _implNewFeature = fetchFeatureTogglesFromSomehere();
public static boolean checkEnabledFeatures(String searchFeature) {
return isEnabled(searchFeature);
}
#Override
public boolean isEnabled(String searchFeature) {
if (Arrays.asList(_implNewFeature).contains(searchFeature)) {
return true;
}else {
return false;
}
}
private String [] fetchFeatureTogglesFromSomehere() {
// TODO get the CONFIG from somewhere
enabledFeatures = new String [2];
enabledFeatures[0] = "new-feature1";
enabledFeatures[1] = "new-feature2";
return enabledFeatures;
}
}
So the workflow is:
1. I start the Application
2. Main method checks the enabled features via FeatureDecisions.java
3. In Feature Decisions i implemented the Interface
I getting the error:
Cannot make a static reference to the non-static method isEnabled(String) from the type FeatureDecisions
May Someone can help me out?
The only way to use an instance method is to have an instance on which to call it. Your checkEnabledFeatures is static, so it doesn't receive an instance you can use (as this). To use an instance method, it would need to create an instance. But obviously that's not what you want here.
Java's interface construct is for defining the interface that instances implement. Java doesn't have the concept of a "static interface" that a class must implement. On the rare occasions when that's needed, it's usually implemented using reflection (perhaps with a class-level annotation to indicate that the class has the necessary feature).
You would have to instantiate the FeatureDecisions class.
public static boolean checkEnabledFeatures(String searchFeature) {
return new FeatureDecisions().isEnabled(searchFeature);
}
or make all members static.
Additional info: There are frameworks like togglz that do this for you.
There's no way to do that. The closest can get is to use the singleton pattern (though lots of people - myself included - would discourage it).
public enum FeatureDecisions implements AppConfiguration
{
INSTANCE;
public String [] enabledFeatures;
public String [] _implNewFeature = fetchFeatureTogglesFromSomehere();
public boolean checkEnabledFeatures(String searchFeature) {
return isEnabled(searchFeature);
}
#Override
public boolean isEnabled(String searchFeature) {
//...
}
}
Your call would then change from:
FeatureDecisions.checkEnabledFeatures(...)
to
FeatureDecisions.INSTANCE.checkEnabledFeatures(...)
It's also worth noting that checkEnabledFeatures doesn't actually do anything besides defer to isEnabled. You could scrap the former and just call the latter directly.
There are several (5+) classes, in code I cannot change, that I need to extend by a few fields. Is there any way to do this without writing (and editing every time I need to change something) the almost exactly same code 5 times? So is there any more elegant way than this:
class Subclass1 extends Superclass1 {
private String newField;
public String getNewField() {
return newField;
}
public void setNewField(String newField) {
this.newField = newField;
}
}
class Subclass2 extends Superclass2 {
private String newField;
public String getNewField() {
return newField;
}
public void setNewField(String newField) {
this.newField = newField;
}
}
//...
I do NOT want multiple inheritance, I want 5 seperate subclasses - just without the duplicate code, because the subclasses all add exactly the same.
The only alternative I can think of is copying the original classes and having the copy extend a Superclass which is probably even worse.
No, you can't do this in Java. You can in certain other JVM-based languages, such as Scala (traits). However, if you must use plain Java, you might consider the following:
Determine the (hopefully single) purpose of the fields you are adding, and the behavior that you want.
Create a new class encompassing all of the fields and the new methods. For example:
public class ExtraFields // Don't use this name!
{
private String myExtraField1;
private String myExtraField2;
// etc.
public void doSomethingWithExtraFields() {
// etc.
}
}
Then, you could take one of the following approaches:
Subclass each of the five classes, and add one field, which is an instance of the class you created above, and delegate behavior accordingly. You will have to use this approach if you must have the extra fields in places where you must pass in one of your five classes. For example:
public class Subclass1 extends Superclass1
{
private ExtraFields extraFields;
public MySubclass()
{
super();
extraFields = new ExtraFields();
}
public void doSomethingWithExtraFields()
{
extraFields.doSomethingWithExtraFields();
}
}
Create a new wrapper class that contains an instance of both your new class created above, and one of those five subclasses. You can make this typesafe using generics. For example:
public class Wrapper<T> // Don't use this name either...
{
private ExtraFields extraFields;
private T myClass;
public Wrapper(T myClass) {
this.myClass = myClass;
this.extraFields = new ExtraFields();
}
}
In this second approach, you don't strictly need the ExtraFields class. But it's still often a good idea to do this so as to encapsulate related functionality.
Hope that helps!
Since you can't change the base classes, it's impossible to eliminate the redundancy. Eric Galluzzo's idea to store the extra fields in a separate class is the best one so far, but I don't know if that's practical in your case. If it isn't, create an interface that defines the extra fields. You'll still have to do a lot of repetitive typing, but at least you'll know immediately when you've made a mistake.
You could use a generic wrapper class, as long as it wouldn't be too tedious to change the rest of the code that works with it.
class Wrapper<E> {
private E obj;
private String newField;
public Wrapper (E obj) {
this.obj = obj;
}
public E get() {
return obj;
}
public String getNewField() {
return newField;
}
public void setNewField(String newField) {
this.newField = newField;
}
}
Let's say there's a class that I use extensively and is returned by a method.
CommonClass obj = getCommonObject();
Now I want to extend this class to create some utility method to avoid repeating myself.
public CommonClassPlus extends CommonClass {
public String dontRepeatYourself() {
// the reason I'm creating a subclass
}
}
Of course I would like to use my improved class for the method above, however, downcasting isn't allowed.
CommonClassPlus obj = getCommonObject();
//Cannot cast to CommonClassPlus
How can I use the method dontRepeatYourself() if I can only work with the object that is an instance of the superclass?
CommonClass and getCommonObject() are from an external library and I cannot change them.
You cannot add behavior to an existing instance in Java (like you could in JavaScript, for example).
The closest you can get in Java is the Decorator pattern:
CommonClassPlus obj = decorate(getCommonObject());
where decorate() is
public CommonClassPlus decorate(CommonClass x) {
return new CommonClassPlus(x);
}
This approach creates a potentially huge amount of boilerplate because it must delegate each method call to the wrapped instance. If a method in CommonClass is final and there is no interface you can reimplement, then this approach fails altogether.
In most cases you will be able to get along with a simple static helper method:
public static String dontRepeatYourself(CommonClass x) {
...
}
If CommonClass is from an external library, you probably want to wrap it in an Adapter Pattern anyway, using the principle of Composition over Inheritance.
This gives you complete control if you want to, say, change the library you're using, and allows you to add functionality like dontRepeatYourself().
public class CommonClassAdapter implements MyAdapter {
private final CommonClass common;
private final String cachedResult;
// Note that I'm doing dependency injection here
public CommonClassAdapter(CommonClass common) {
this.common = common;
// Don't expose these because they shouldn't be called more than once
common.methodIOnlyCallOnce();
cachedResult = common.anotherMethodIOnlyCallOnce();
}
#Override
public void someMethod() {
common.someMethodWithDifferentName();
}
#Override
public String dontRepeatYourself() {
return cachedResult;
}
}
Note also that most modern IDEs have things like Eclipse's Source -> Generate Delegate Methods to make this process faster.
In an effort to reduce my NCSS count of a class (~850), I have split all of the methods into their own classes and to make things easier, I extend an abstract class that holds all the helper functions.
AbstractMethod.class
public class AbstractMethod {
protected String requestWebPage(URL url) {
// download a webpage as a string
}
}
Example "account" subclass
public class AccountData extends AbstractMethod {
public String getAccount(String sessionId){
String webPage = requestWebPage("http://google.com/"+sessionId);
system.out.println(webPage);
return webPage;
}
}
I have approx 10 of these method classes and would like to only initialize them when one of the methods in the main/base class is called:
public class MyBaseClass() {
private static AccountData ad;
public MyBaseClass() {
ad = new AccountData(); // Is there a better way?
}
public String getAccount(String sessionId) {
return ad.getAccount(String sessionId);
}
}
I have tried to create an initialise function in the MyBaseClass class that accepts the subtype as a parameter and create an object based on it's class:
private void initAccount() {
if (ad == null) {
ad = new AccountData();
}
}
but it's ugly and I have to have one per sub-class.
So, what's the "correct" way to do this? Sometimes when the class is called, we will only use 1 or 2 of the methods, so I don't want to have to initialise all the sub-classes each time.
It would seem to me that what you really want is to use static methods rather than abstract helper classes, perhaps along with import static.
That way, the class(es) defining those methods would, as you wish, only be initialized once the methods are actually called.
You would also not limit your inheritence structure in general to where the methods happen to be defined.
That's assuming you don't use any instance data for those methods, of course; but from the looks of your sample code, it doesn't seem that way.
Instantiating classes in Java is cheap. If the classes are not doing anything substantial in their contructors then just do
public String getAccount(String sessionId) {
AccountData ad = new AccountData();
return ad.getAccount(String sessionId);
}
Don't optimize where it's not nessesary. Profile your code before. You might be suprised how wrong your assumtions are (I know I was many times).
I have following classses
Hello.java
package speak.hello;
import java.util.Map;
import speak.hi.CustomMap;
import speak.hi.Hi;
public class Hello {
private Hi hi;
Hello(Hi hi) {
this.hi = hi;
}
public String sayHello() {
return "Hello";
}
public String sayHi() {
return hi.sayHi();
}
public Map<String, Object> getMap() {
return hi.getMap();
}
public void clearMap() {
hi.getMap().clear();
}
public void discardMap() {
CustomMap map = (CustomMap) hi.getMap();
map.discard();
}
public static void main(String[] args) {
Hello hello = new Hello(new Hi());
System.out.println(hello.sayHello());
System.out.println(hello.sayHi());
System.out.println(hello.getMap());
hello.clearMap();
System.out.println("--");
hello.discardMap();
}
}
Hi.java
package speak.hi;
import java.util.HashMap;
import java.util.Map;
public class Hi {
public String sayHi() {
return "Hi";
}
public Map<String, Object> getMap() {
return new CustomMap<String, Object>();
}
}
CustomMap.java
package speak.hi;
import java.util.HashMap;
public class CustomMap<K, V> extends HashMap<K, V> {
private static final long serialVersionUID = -7979398843650044928L;
public void discard() {
System.out.println("Discarding Map");
this.clearCache();
this.clear();
}
#Override
public void clear() {
System.out.println("Clearing Map");
super.clear();
}
private void clearCache() {
System.out.println("Clearing Map");
}
}
This works fine until I remove public access specifier from CustomMap
package speak.hi;
import java.util.HashMap;
class CustomMap<K, V> extends HashMap<K, V> {
private static final long serialVersionUID = -7979398843650044928L;
public void discard() {
System.out.println("Discarding Map");
this.clearCache();
this.clear();
}
#Override
public void clear() {
System.out.println("Clearing Map");
super.clear();
}
private void clearCache() {
System.out.println("Clearing Map");
}
}
Compiler yells that
The type speak.hi.CustomMap is not visible
Now If I don't have options to modify speak.hi.CustomMap (third party jar etc..) Is there any way I could still use CustomMap from speak.hello.Hello?
One option that I know is to move speak.hello.Hello to speak.hi.Hello as Now Hello is in package speak.hi it can access package private Class Hi
Is there any other way to do this ? Using reflection perhaps ?
EDIT :Updated with additional details as requested by #StephenC
Is there any other way to do this ? Using reflection perhaps ?
Yes. Reflection can be used to bypass the Java access rules, if your application has full privilege.
For instance, to access a private field of an object from a different class, you need to:
Get the object's Class object.
Use the Class.getDeclaredField(...) method to get a Field object for the field.
Call Field.setAccessible(true) to turn off the access check.
Call Class.getField(object, Field) to get the field's value (or boxed value if it is a primitive type).
If the class itself is not accessible, you need to make sure that you don't refer to the classes identifier in your source code ... 'cos that will result in a compilation error. Instead, assign its reference to (say) variable of type Object or of some other visible supertype, and perform more specific operations on the instance reflectively.
As you might imagine, this is tedious and error prone. You'd be advised to find a better way, like:
getting the suppliers of the classes to fix whatever is causing you to need to break the visibility restrictions,
getting the suppliers of the classes to change their visibility,
finding another way to use the classes that doesn't require breaking open their abstraction, or
ditching them and finding (or writing) something better.
(Generally speaking, if you have to break open an abstraction then something is wrong with either the abstraction itself or the way you are using it.)
Finally, I should add that untrusted code is (should be) run in a security sandbox that blocks the use of the key reflective operations.
Following method Invokes default scoped class method using reflection
public void discardMap() {
//CustomMap map = (CustomMap) hi.getMap();
//map.discard();
try {
Object o =hi.getClass().getMethod("getMap").invoke(hi);
Method m = o.getClass().getMethod("discard");
m.setAccessible(true);
m.invoke(o);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It may not be possible because:
Class :
Accessible to class from same package?
public : yes
protected : yes
default : yes
private : no
Accessible to class from different package?
public : yes
protected : no
default : unless it is a subclass
private : no
I don't recommend to use non-API classes as they might change in any future version and can break your code.
How did you find out about this class? Is it an Open Source library?
Try to contact the authors of the library, tell them your use case and find a way with them to offer a public API. If it's an open source library you could help them by providing a patch.
Adding this solution for sake of completeness.
One option that I know is to move speak.hello.Hello to speak.hi.Hello as Now Hello is in package speak.hi it can access package private Class Hi
package speak.hi;
public class Hello {
private Hi hi;
Hello(Hi hi) {
this.hi = hi;
}
public String sayHello() {
return "Hello";
}
public String sayHi() {
return hi.sayHi();
}
public static void main(String[] args) {
Hello hello = new Hello(new Hi());
System.out.println(hello.sayHello());
System.out.println(hello.sayHi());
}
}
Not possible. The security model is this : a model to provide security :) If you designed class Hi and delivered it to customers with private access, you wouldn't like them to be able to bypass your restrictions, would you?
I would think that if the authors of a library did not make a particular class part of the public API, it is because they don't want other people using it. You should respect the decision even though you can break it using reflection. Using private API is simply bad programming.
1st class is in package a.b.c.class1 but class1 is private as well as abstract
2nd class is in package a.b.c.class2 extends class1 but class2 is public
3rd class is in package x.y.z.class3
So as to access class1 in class 3 you can write something like:-
Class baseClass = (new class2()).getClass();
and use the instance of its superclass then use:-
baseClass.getSuperClass();
and use it wherever you want.
But then again the baseclass was made abstract and private for a reason hence not advisable to do so but then again this solution could be used as a workaround.
I think by default the class will be "default" (package private, you can say), NOT "private". So it can be accessed with in the same package.
Moreover, you CANNOT make any *top level class Private in Java.
And if you want make a class default and still be able to access it in other package then what will be the purpose of having access specifiers (modifiers) ??
you either need to make class public or move to the same package.
Not Possible you can not create your Hi class as private.