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.
Related
I know that an instance of a class with a private constructor can be created using reflection but is there any way to make sure that the instance of the class can only be created within the same class using its own private constructor?
Let's take an example of a class Test, with a private constructor.
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Test
{
private Test() //private constructor
{
}
}
public class Sample{
public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
{
Class c=Class.forName("Test"); //specify class name in quotes
//----Accessing private constructor
Constructor con=c.getDeclaredConstructor();
con.setAccessible(true);
Object obj=con.newInstance();
}
}
My question is - is there any way to ensure that the instance of the class can only be created within the same class and not from outside using reflection or any other method?
There are several ways to prevent the creation - but it is hard to tell which one is appropriate for your use-case:
Throw an exception in the constructor
You can either unconditionally throw an exception - making it (near) impossible to instantiate an instance - or only throw under certain conditions.
Some conditions can be:
Inspecting the caller - using StackWalker for example.
Passing a "secret" passphrase to the constructor. JMH does this for example.
Use Java Modules.
As other modules can't deeply reflect into other named modules, Constructor.setAccessible will not work on your class outside of your own module.
Of course this restriction doesn't apply to your own module - but you should be able to control your own module ;).
Install a SecurityManager.
Prevents Constructor.setAccessible from returning successfully.
But the security manager is deprecated for removal, so I can't recommend it's use.
Note: Most of those solutions can be circumvented in some way. And it is sometimes possible to add additional defenses against that. But at the end, it'll become a game of cat and mouse.
One way you already mentioned in comments by using Exception & another way to do this is using Thread.currentThread()
package app.test;
public class Test19 {
..
private Test19() {
if (Thread.currentThread().getStackTrace()[1].getClassName() == "app.test.Test19") {
// initialize member fields etc.
} else {
throw new IllegalAccessException();
}
}
}
I have an interface defined as follows:
public interface Cache {
}
Then an abstract class implementing the above:
public abstract class AbstractCache implements Cache {
}
Then a concrete class inheriting from above:
public class RealTimeCache extends AbstractCache {
}
Then another class defined as follows:
public class CacheProbe {
public static <T> T probe(T base) {
return (T) Proxy.newProxyInstance(
base.getClass().getClassLoader(),
new Class[]{Cache.class},
new MethodCountInvocationHandler(base) // I am not mentioning this class as it's irrelevant
);
}
}
I have a class as follows which is using all of the above:
public class CacheLoader<T extends Cache> {
public T load() {
T result = getResult(...);
CacheProbe x = new CacheProbe(result);
return x.probe();
}
}
Lastly, the lines causing the issue (located outside above classes):
final CacheLoader<RealTimeCache> cacheLoader = getNewLoader(); //Method of this method is irrelevant and unchangeable
RealTimeCache x = cacheLoader.load(); //This is the line which is causing a runtime issue
Problem is, at run time the following exception is thrown at the last line mentioned above:
java.lang.ClassCastException: com.sun.proxy.$Proxy57 cannot be cast to RealTimeCache
However I don't see how this is possible because the dynamic proxy class generated is based on Cache.
How do I fix this ?
Please note that I can only change CacheProbe class in order to fix this. Cache, AbstractCache, RealTimeCache, CacheLoader and those last two lines are unchangeable.
However I don't see how this is possible because the dynamic proxy class generated is based on Cache.
Yes, the docs for java.lang.reflect.Proxy say
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
(emphasis added)
Thus, you cannot use Proxy to create (an instance of) a subclass of an arbitrary class of your choice.
How do I fix this ?
You can create an ordinary subclass of RealTimeCache, and return an instance of that. Proxy is meant primarily to serve for interfaces that are not known until runtime, and in that case the only way to interact with them anyway is the interface type. That's not your scenario.
If necessary, you can implement such a subclass in terms of a MethodCountInvocationHandler, just as your proxy class uses, but I'm sure it would be easier to implement whatever tooling that is supposed to provide directly.
I know Java loads Classes in first Access (creating new Instance, calling static method or static field), but in this simple example I try to execute a jar file that uses some classes which there aren't in my ClassPath at run time. I expect (because of loading classes in first access) print my messages in static block and main method before an exception occurred. but I got "Exception in thread "main" java.lang.NoClassDefFoundError: com/example/DateAbstract" and nothing printed.
This occurred when I used an abstract class or interface in main class which that classes or interfaces are in another jar file.
public class Driver {
static { System.out.println("I am first.[static block]"); }
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
in my another jar :
public class CustomDate extends DateAbstract {
#Override
public String sayDate() {
return new Date().toString();
}
public abstract class DateAbstract {
public abstract String sayDate();
}
when I use this code for add my classes to classpath at runtime. nothing changed. I got execption before execute static block.
public class Driver {
static {
System.out.println("I am first.[static block]");
try {
URL url = new File("lib/DateApi.jar").toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader,url);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
}
Questions :
why is this happening and how to solve it ?
It’s not correct to say that in Java classes are loaded on their first access. You are confusing this with the initialization of a class, which implies executing the Java code of static initializer blocks and field initializers. The loading and verification might happen at an earlier time; the specification provides some freedom to the JVMs in this regard.
The key point here is that your main method instantiates an object of type CustomDate, stores it into a variable of the compile-time type DateAbstract and then tries to invoke sayDate() on that variable. This combination of instantiating CustomDate and invoking DateAbstract.sayDate() on it requires the verification of its correctness, i.e. whether CustomDate is a subtype DateAbstract. So the loading of these two classes will already happen at verification time.
You can easily check that this is the cause. If you change the type of the local variable date to CustomDate, the instantiated type and the receiver type of the method invocation are the same, so the correctness can be proven without loading the type, so it will be indeed deferred to the actual attempt to instantiate CustomDate, hence the messages will be printed.
Still, the loading time is an implementation-specific detail. A different JVM could load the referenced classes eagerly, even if they are not required for verification. The only safe way to ensure a deferred loading, is to use dynamic loading, e.g. Class.forName(String). Note that within the class detached this way, all types might be again referenced ordinarily. So if you do the dynamic loading once after the class path has been adjusted, there is not much impact on how you have to write the code nor its performance. Of course, having the code adjusting the class path and the code depending on it within the same class won’t work reliably.
What I know till now:
Instance of Servlet is first created by container via reflection and no argument constructor gets used.
Then parameterized init method gets called.
Also it is suggested that we should not create a constructor in servlet class as it is of no use. And I agree with that.
Lets say, I have created a no argument constructor in servlet class and from within that I am calling a parameterized constructor. My question is, will it be called by the container?
public class DemoServlet extends HttpServlet{
public DemoServlet() {
this(1);
}
public DemoServlet(int someParam) {
//Do something with parameter
}
}
Will DemoServlet() be called by the container and if we put some initializing stuff inside it, it will be executed? My guess is yes but it's just a guess based on my understanding.
This might be pretty useless, I am asking out of curiosity.
DemoServlet() will be called (as you are overriding the defined no-arg constructor in HttpServlet (which is a no-op constructor).
However the other DemoServlet(int arg) will not be called.
You are correct with your guess. DemoServlet() would be called by the container and any initialization code within it would be executed - even if that initialization is done through constructor-chaining And as a matter of fact this is a good way to have dependency injection and create a thread-safe servlet which is testable Typically it would be written this way
public class DemoServlet extends HttpServlet
{
private final someParam; //someParam is final once set cannot be changed
//default constructor called by the runtime.
public DemoServlet()
{
//constructor-chained to the paramaterized constructor
this(1);
}
//observe carefully that this paramaterized constructor has only
//package-level visibility. This is useful for being invoked through your
// unit and functional tests which would typically reside within the same
//package. Would also allow your test code to inject required values to
//verify behavior while testing.
DemoServlet(int someParam)
{
this.param = param
}
//... Other class code...
}
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..
}
}