1

I've asked a similar question but I prematurely accepted an answer. Here it is again.

Context: I'm trying to instantiate the constructor of a class which I imported as a Maven dependency via it's coordinates.

Problem: The problem I have is that the particular constructor of this class, is invisible to me because it has no access modifier associated with it so it is default, meaning I can't access it from outside.

Example: The class I'm trying to use is here:

public class SomeClass {

   // Notice no access modifier here so it's package-default
   SomeClass(Log log, File in, File out) {
      some stuff ...
   }

   // public constructor
   public SomeClass() {}

   // Method 1
   public void compiler(File schema) {
      some stuff ...
   }

   // Method 2
   public void linker(File attribute) {
      some stuff ...
   }
}

Here is my toplevel in a separate project:

public class TopLevel {

   public void testSomeClass() {

      Constructor<SomeClass> constructor = SomeClass.class.getDeclaredConstructor(Log.class, File.class, File.class);
      constructor.setAccessible(true); 

      // Default access level 
      SomeClass builder = constructor.newInstance(log, contentDirectory, outputDirectory); 

      //Here is where the problem occurs
      builder.compiler(schemaFile);
   }
}

Comment: This does not seem to work, with the above implementation in my toplevel, constructor and the methods in the class are now all visible to me and I am able to call them but I get an exception thrown at me from ReflectiveCallable abstract method which when invoked, throws the exception from the reflected method, rather than wrapping it in an InvocationTargetException. It seems there is something wrong with the way the class DecisionTableBuilder was instantiated. Hence my question here.

Am I doing this right? Is there another way to reflect a default access modified constructor/method? When I explicitly reflect a constructor, do I also need to reflect the classes methods too?

Any help would be must appreciated. Thanks everyone in advance

EDIT:

Here is my stack trace, if someone can make sense of this...

java.lang.NullPointerException
    at com.intuit.ctg.tla.compilers.SomeClass.compile(SomeClass.java:95)
    at com.intuit.ctg.tla.compilers.qa.testSomeClass.testSomeClass(testCompilerLinker.java:80)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

I've followed this stack trace to this line of code:

// This piece of code recursively searches in directory treesDirectory and
// lists all file with xml extentions
Collection<File> flowchartFiles = FileUtils.listFiles(treesDirectory, mapExtension, true);

somehow treesDirectory (type File) is getting a NULL pointer even though I pass this via the constructor, here as the 2nd argument:

public static File treesDirectory = new File("src/test/resources/input_graphs/"); 
public static File outputDirectory = new File("src/test/resources/output"); 
public static Log log;

SomeClass builder = constructor.newInstance(log, treesDirectory, outputDirectory); 

something funny is happening in the reflected constructor... Anybody have any ideas? I've been on this for 2 days now...

mosawi
  • 1,283
  • 5
  • 25
  • 48
  • 1
    Please post a complete and reproducible example and a full stack trace of an exception, if you have one. – Sotirios Delimanolis Jul 19 '15 at 01:03
  • 1
    AFAIK the constructor is intentionally hidden from you, there is no legal way of accessing it. This is how people distribute software. – Sreekar Jul 19 '15 at 01:24
  • @Sreekar this is the purpose of Java Reflections, gives you access to private and default access modified constructors and methods – mosawi Jul 19 '15 at 01:34
  • I agree, someone asked for more detail. I'm going to remove some code to make it less verbose – mosawi Jul 19 '15 at 02:02
  • If your error truly occurs on that last line, where you already managed to get an instance of `DecisionTableBuilder`, then I don't see how reflection is an issue anymore. But without a proper error message and stacktrace, it's all speculation. – sstan Jul 19 '15 at 02:48
  • Please post an MCVE, we can only guess until then. – Sotirios Delimanolis Jul 19 '15 at 06:15

1 Answers1

1

A Default Constructor

Can only be accessed by classes in the same package. You could create your own factory (or builder) in that package and give it public access. It's also possible that one is already provided in your API.

JLS Example 6.6-4. Access to Default-Access Fields, Methods, and Constructors

says (in part)

If none of the access modifiers public, protected, or private are specified, a class member or constructor is accessible throughout the package that contains the declaration of the class in which the class member is declared, but the class member or constructor is not accessible in any other package.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249