class Main {
public static void main(String[] args) {
....
}
}
Starting the program through the shell: java Main works as expected but starting the program through ant:
<target name="run" depends="cmp">
<java classname="Main" classpath="."/>
</target>`
causes this error:
java.lang.IllegalAccessException: Class org.apache.tools.ant.taskdefs.ExecuteJava can not access a member of class Main with modifiers "public static"
JLS Section 12.3.3 Resolution of Symbolic References:
IllegalAccessError: A symbolic reference has been encountered that
specifies a use or assignment of a field, or invocation of a
method, or creation of an instance of a class, to which the code
containing the reference does not have access because the field or
method was declared private, protected, or default access (not
public), or because the class was not declared public.
So org.apache.tools.ant.taskdefs.ExecuteJava can't execute the method because it's enclosing class is private, but if I start the jvm pointed at a .class with a private method, it doesn't go through the same security mechanism?
This question is similar but I still don't understand
The answer is all in the question you linked to. When you run it through the JVM it has access to absolutely everything regardless of access level. When you run it through ant, which itself is another java program, it has to obey by the same rules as any other program - which means that it cannot see your main method.
If you declare your class as public class Main the problem should go away.
As to why the jvm has made this decision to allow access to private classes when starting is another matter indeed. As per the specification
12.1.4 Invoke Test.main
Finally, after completion of the initialization for class Test (during
which other consequential loading, linking, and initializing may have
occurred), the method main of Test is invoked. The method main must be
declared public, static, and void. It must accept a single argument
that is an array of strings. This method can be declared as either
public static void main(String[] args) or public static void
main(String... args)
This specifically states that the method must be public but says nothing about the class in questions, which why it works when you invoke main through the VM directly.
Try to add public modifier to the class like this:
public class Main {
public static void main(String[] args) {
....
}
}
Use public access-modifier.
Eg:
public class Main {
public static void main(String[] args) {
// Your code..
}
}
Related
I want to create an abstract class with a main method, to prevent developers who extend it from having to implement the main method. I also want to control what happens in the main method.
The abstract base class that I'm writing extends NanoHTTPD, and you start the server by calling ServerRunner.run() with the parameter being a class object of the type of the class that you want to run.
Here is what I have so far:
public abstract class FlexibleServer extends NanoHTTPD
{
public DeadSimpleMicroserver(int port)
{
super(port);
}
public static void main(String[] args)
{
ServerRunner.run(FlexibleServer.class);
}
}
The problem is that since this class is abstract, future developers will be extending the class, so I need the parameter to ServerRunner.run() to be the ACTUAL type of the subclass, so I can't use FlexibleServer.class.
I tried changing the parameter to this.class, but then I get the compile error that "this" cannot be referenced from a static context (because main() is static).
How can get a class object of the actual subclass from main()?
If the class that you're going to pass at runtime is dynamic, then you cannot call it with a hard-coded class name. You will have to change your call to run so that you pass it either an instance of the actual class, or you would have to dynamically load the class given, for example, main method arguments.
With the above change, your problem gets resolved.
For example, if you're loading the class dynamically:
ServerRunner.run(Class.forName(args[0]));
Assuming the app will be called with the actual class name.
Alternatives include redesigning your code such that either a class name, an instance, or class object is passed in by the caller
A framework I once worked on had a base class like this, and we added a method like this:
public abstract class FrameworkServer {
// framework stuff
protected static void main(String[] args, FrameworkServer instance) {
// parse args
// actually start the instance running
}
}
And a specific server instance would need to add its own main method like so:
final class MyServer extends FrameworkServer {
public static void main(String[] args) {
main(args, new MyServer());
}
}
There is a small bit of boilerplate here for each server, but that allows you do avoid reflection and to make the code much clearer. As a bonus, the concrete subclasses can now add their own arguments to their server's constructor, which is often very useful for unit-testing.
I'm reading the draft of the Java 9 specification but this phrase is not clear to me:
The opens directive specifies the name of a package to be opened by the current module. This makes public and protected types in the package, and their public and protected members, be accessible to code in other modules at run time only. It also makes all types in the package, and all their members, be accessible via the reflection libraries of the Java SE Platform.
If the opens makes public and protected accessible at runtime only, what does meaning that all types in the packages area accessible via reflection?
I don't understand the difference between runtime and reflection.
It seems like the opened package makes accessible only public and protected at runtime (via reflection?) and also other packages not specified with type and members accessible vie reflection (also private...).
Let's say you write some code that uses a public class from a library.
import somelibrary.somepackage.SomeClass; // <-- public class from a library.
public class Main {
public static void main(String[] args) {
SomeClass.doSomething();
}
}
You then compile this code, and it compiles fine, since the class you're using is public.
Now, in the next version of the library, the package is added to a module, but not exported. That means that if you try to run your code with this new module on the runtime module path, it would throw an exception because you're trying to access an encapsulated package.
In order to make your code work again, you could use the command line option to open this module to your code, so that it can continue to use the encapsulated package.
Alternatively, the creator of the library could add opens somepackage; to the module definition of the library. That would allow you to run your code using this new version, but not compile with it. I.e. the public and protected members are only accessible at runtime, but there is no reflection involved.
The same goes for when you extend a class, and want to access a protected member of a super class that is in the encapsulated package.
But the opens directive does not change the fact that, if in the next version of a library, a method or field is made private, that you get an IllegalAccessError if you try to use it:
class SomeClass { // <-- the class in the library
public static void doSomething() {
System.out.println("doSomething"); // contrived example code
}
}
...
public class Main {
public static void main(String... args) throws Exception {
SomeClass.doSomething(); // this call compiles fine,
}
}
Then, in the next version of the library doSomething is made private:
private static void doSomething() {...}
And re-compiled. But if you try to run the old version of Main with the new version of SomeClass you get an IllegalAccessError.
In short, opens only works for members that are still public or protected in the new version of the library.
However, in the case of reflection, you can always access a private member, by using setAccessible(true):
public static void main(String... args) throws Exception {
Method m = SomeClass.class.getDeclaredMethod("doSomething");
m.setAccessible(true);
m.invoke(null); // works Fine
}
So in the case of reflection, opens would also make encapsulated private members accessible again.
A package opened by a module, may be qualified or unqualified.
The opens directive in a module declaration declares a package to be
open to allow all types in the package, and all their members, not
just public types and their public members to be reflected on by APIs
that support private access or a way to bypass or suppress default
Java language access control checks.
--Documentation
class HelloWorld {
public static void main(String arg[]) {
System.out.println("Hello World!");
}
}
Using javac HelloWorld.java and java HelloWorld, the code compiles and runs well. Since default access specifier in Java is package, how is it possible? It must have protection from outsider...
Access modifier restricts access during compile time. But it is allowed to load a class with any access modifier, use reflection to find the main method and run it. This is what java tool does when lanching from a class. See http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html
Default Access modifier means you can only access that class in that package.
what you are doing here is, running and compiling the class.
This has nothing to do with modifiers and accessibility.
You will always Run & Compile classes like that.
What matters is that your class is accessible in the class or package that is being run.
You can not access a class with Default modifier in sub package or other package. A default class will only be accessible i the same package, otherwise you will get compile time error.
As far as your code is concerned you are doing nothing like that.
Suppose -
class HelloWorld {
public static void main(String arg[]) {
System.out.println("Hello World!");
}
}
And
Class Hello extends HelloWorld{
// some code here
}
Now if you compile class Hello, then it will give you following error.
class, interface, or enum expected
When I create a new main.java file in the default package in my Eclipse project, it generates a main method that looks like:
public static void main(String[] args)
{
}
This immediately raises a warning that says This method has a constructor name. The suggested fix is to remove the void:
public static main(String[] args)
{
}
Now rather than a warning, I get an error: Illegal modifier for the constructor in type main; only public, protected & private are permitted. If I remove the static, my code now looks like:
public main(String[] args)
{
}
This time, I still get an error, but a different one that says:
Error: Main method not found in class main, please define the main method as:
public static void main(String[] args)
Argggh! But that takes me right back to where I started. How do I define the main method so that I don't get any errors or warnings?
I'm using Eclipse Juno Service Release 2 and JavaSE-1.7. Please note, I'm very new to Java; I come from a C# background. Also, this is probably a duplicate question, but I can't find it.
Don't call your class main, but Main.
In general, stick to the Java coding standards: start class names with a capital (Main instead of main) and you won't run into these problems.
If you name the file main.java the class has to be named main too, which is against standard (classes start with a capital letter) but possible. In a class a method named the same as the class is considered a constructor. So to fix your problem and fit the standard rename your class and the file to Main with a capital "M"
Change the name of your class from main to Main or to something else. Also, following the JavaBean API specification, your classes must be in CamelCase with the first letter in capital.
Not 100% related with question, but you should also do not create classes with the names of Java JDK classes, for example String:
public class String {
public static void main(String[] args) {
System.out.println("Try to execute this program!");
}
}
This won't only give problems to compiler/JVM but also for future readers (remember that you are a future reader of your own code as well).
Note: to fix the code above, just refer to java.lang.String class using its full name:
public class String {
public static void main(java.lang.String[] args) {
System.out.println("Try to execute this program!");
}
}
Or even better, change the name of the class.
In java, the class name and file name must match. If you have a file named main.java, then the class name has to be Main too, and in that case, the constructor method would be named main, so you couldn't have a main method.
Change your file and class name to something other than main.
I have code where a variable name is identical to the class name. I.e.:
class Foo {
static public void main(String[] args) {
Integer Foo;
Foo.main(args);
}
}
How can I call the main-method without renaming the variable or the class?
If it's not in the default package you could refer to it via the package name also, e.g.:
packagename.Foo.main(args);
or you can simply refer to main without the class name, e.g.:
main(args);
If class Foo is in a package, you could use the fully qualified name:
my.package.Foo.main(args);
You could also rename variable Foo; it's bad Java style to capitalize variable names. Finally, why would you want to call main from main like that? It's going to overflow the stack very quickly.
Since Integer does not have a main(...) method, this is not a problem.
More generally speaking, if you need to disambiguate, use the full package name.
use the full package name, it works.
package my.pck;
class Foo {
static public void main(String[] args) {
Integer Foo;
my.pck.Foo.main(new String[] { "arg" });
}
}
But why would you want to call main from main like that? its creating infinite loop.
I have code where a variable name is identical to the class name
Why? The simple answer is "don't". The convention is that class names start with a capital and member variable names don't, which takes care of it completely.