Search code examples
javaaccess-specifier

How to Access package private Class from a Class in some other package?


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


Solution

  • 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();
        }
    }