I have a Command class like the following:
public class Command {
...
private String commandName;
private Object[] commandArgs;
...
public void executeCommand() {}
}
I also have a subclass of Command, AuthenticateCommand:
public class AuthenticateCommand extends Command {
...
#Override
public void executeCommand() {
...
}
}
Now imagine a class, Server, that has a method processCommand(Command command). It takes the command param, inspects the commandName field, and uses that name to cast the command to a subclass of Command responsible for implementing the command logic. In this example, you might have a Command with a commandName of "authenticate" and the username and pw stored in the commandArgs array. processCommand() would cast the Command to AutheticateCommand and invoke the executeCommand() method. I'm trying to accomplish this with the following (commandMap is just a Map that maps a commandName to its implementor class name):
public void processCommand(Command command) {
String commandName = command.getCommandName();
String implementorClassString = commandMap.get(commandName);
try {
Class implementorClass = Class.forName(implementorClassString);
Object implementor = implementorClass.cast(command);
Method method = implementorClass.getDeclaredMethod("executeCommand", null);
method.invoke(implementor);
} catch (ClassNotFoundException e) {
logger.error("Could not find implementor class: " + implementorClassString, e);
} catch (NoSuchMethodException e) {
logger.error("Could not find executeCommand method on implementor class: " + implementorClassString, e);
} catch (IllegalAccessException e) {
logger.error("Could not access private member/method on implementor class: " + implementorClassString, e);
} catch (InvocationTargetException e) {
logger.error("Could not invoke executeCommand method on implementor class: " + implementorClassString, e);
}
}
The call to implementorClass.cast() is throwing a ClassCastException. Shouldn't it be able to downcast to the AuthenticateCommand class in this manner?
UPDATE
Some more background. The Server class handles more than just AuthenticateCommands. There could be any number of Command subclasses, depending on the project. I'm trying to make it simple for someone writing a Client to pass a serialized Command object with just a name and arguments. I could force the client to "know about" AuthenticateCommand and all the others, and then serialize those and pass them, but that seems sub-optimal because the only difference between the subclasses is the implementation of executeCommand, which the client doesn't care or know about. So I just want a way to have the Client pass the parent class, and use data within that parent class to cast it to the appropriate subclass.
I suppose I could use newInstance() instead of cast and just create a new object, but that seems wasteful. I suppose I could also do away with the concept of subclasses handling the logic and move those into methods, and then processCommand would call the appropriate method. That feels janky to me as well, though.
Why are you casting at all? You're just trying to call executeCommand, and that's available on Command... so just write:
command.executeCommand();
which should compile and run. It's not clear where the map comes in at all.
As for why the cast is failing... my guess is that the ClassLoader for the command isn't the default ClassLoader at this point, so that implementorClass is the same class, but loaded by a different ClassLoader... which makes it a difference class as far as the JVM is concerned.
EDIT: I'd say your design is broken. The Command object you're being passed isn't fulfilling its role properly. One option would be to have a new RemoteCommand subclass which knows the name, and when its executeCommand method is called, it builds the appropriate subclass instance. And yes, it will need to build an instance of the class. You can't call an instance method on a class without an instance of that class, and you can't make one object "pretend" that it's actually an object of a different type. What if AuthenticationCommand has some extra fields it tries to use? Where would the values come from?
A nicer alternative is to make your serialization/deserialization layer do this, so that by the time you've reached this bit of code, you've already got an AuthenticationCommand - and you can use the code at the top of this answer.
You really need to instantiate it. You can't "convert" a Class<T> to a concrete instance by just casting. Also, the casting should be done the other way round as opposed to your code snippet.
Class<?> implementorClass = Class.forName(implementorClassString);
Command instance = Command.class.cast(implementorClass.newInstance());
instance.executeCommand();
Not to mention that this all is a design smell.
You would be able to downcast only when Command Object actually references Authenticate Command instance at runtime. This is what polymorphism talks about isnt it?
Related
I know I can get the method and classname from StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); but that is not what I want.
I want the class object, so I can access his interface, annotations, etc...
It is possible?
Class<?> classObject = getCallerClass();
I see this question, but that is just for the classname.
How to get the caller class in Java
Edit: Now I'm passing the class this way:
someService.dummyMethod(foo1, foo2, new Object(){}.getClass());
someService(String foo1, int foo2, Class<?> c) {
// stuff here to get the methodname,
// the interface of the class and an annotation from the interface.
}
I call someService from a lot of different classes, If is not possible I will continue this way, but If there is a way to get the caller class at runtime I prefer that way.
If you're using Java 9+ you can use java.lang.StackWalker.
public void foo() {
Class<?> caller = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.getCallerClass();
}
However, since StackWalker is thread safe it might be beneficial to create an instance and store it somewhere (rather than create a new instance every time the method is called).
Javadoc of getCallerClass():
Gets the Class object of the caller who invoked the method that
invoked getCallerClass.
This method filters reflection frames, MethodHandle, and hidden frames
regardless of the SHOW_REFLECT_FRAMES and SHOW_HIDDEN_FRAMES options
this StackWalker has been configured with.
This method should be called when a caller frame is present. If it is
called from the bottom most frame on the stack, IllegalCallerException
will be thrown.
This method throws UnsupportedOperationException if this StackWalker
is not configured with the RETAIN_CLASS_REFERENCE option.
Get the classname using the code of your linked question: How to get the caller class in Java
Then use the classname to retrieve the class, using code from here: Getting class by its name
Complete code:
String callerName = Thread.currentThread().getStackTrace()[2].getClassName();
try {
Class<?> caller = Class.forName(callerName);
// Do something with it ...
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
(community answer, since only mix of existing answers).
I have a suite that can run a few operations with different parameters. The operations and their parameters are provided in an XML config file.
There is a separate class implementing each operation. All of these classes extend an abstract Operation class, so once the class is created it can be handled in the same way in the code, whatever the actual operation is.
However, I do need to create the classes. And so far I see two ways of doing it:
a switch statement:
Operation operation;
switch (operationName) {
case "OperationA":
operation = new OperationA();
break;
case "OperationB":
operation = new OperationB();
break;
default:
log.error("Invalid operation name: " + operationName);
return true;
}
A runtime lookup of a class name. I never tested this option, but it seems to be something like:
Operation operation = (Operation)Class.forName(operationName).newinstance();
The first option seems unwieldy. The second option seems to trust the config too much, though I am not sure about this.
Perhaps I should just verify that operationName is a member of a predefined set or list that contains all my operations (or else set thepossible values in stone in an XML schema and verify the config against it), then use the second option? Or is there something better?
I would prefer to use the second option.
An example class. (Note that the default constructor is required because it is called by .newInstance(). You can also refer to this question: Can I use Class.newInstance() with constructor arguments? if you want to create a new class and use a constructor with parameters.)
package com.mypackage;
public class SomeObject {
public SomeObject() {}
}
How to create an instance of that class:
try {
// you need to use the fully qualified name, not just the class name
SomeObject object = (SomeObject) Class.forName("com.mypackage.SomeObject").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// here you can handle incorrect config in your XML file
}
You can also have a list of qualified names in another configuration file or property and check against that list before attempting to create a class.
Is something like that possible.
List<?> myList = getMyList();
class cls = class.forname("com.lab.myClass");
cls = myList.get(0);
cls.getValue();
Create an Instance with the fully-qualified name of a class and use their declared Methods?
No, if you call Class.forName, at compile time you know nothing about the returned Class instance. You don't even know that it represents a class; it might be an interface for example. In particular, if it is a class and you create an instance of it, you cannot call any methods of it except those which are already defined in Object because, at compile time, the compiler cannot check whether these methods exist.
The are two solutions:
First, you can use reflection to find out about the methods the class has, and to call these methods. This is very cumbersome.
Second, if you use Class.forName to dynamically load classes at runtime, often you know something about the classes you load. For example, you might know that the class implements a certain interface. Then you can cast the result of newInstance to this interface and then call the methods defined in this interface directly.
For example:
// in file Plugin.java
interface Plugin {
void doSomething();
}
// in file Main.java
public class Main {
...
void runPlugin() {
try {
Class<?> pluginClass = Class.forName("pkg.name.MyPlugin");
Plugin plugin = (Plugin) pluginClass.newInstance();
plugin.doSomething();
}
catch (...) {
// catch the necessary exceptions
}
}
}
Suppose I have a class Foo in package my.package which contains some static fields.
I want to use reflection to get the values of those static fields.
I know I can write my.package.Foo.class.getDeclaredField(... but this is unsatisfactory as I'm hardcoding the class and package names.
I'd like to use this.class.getDeclaredField(... but this is invalid in Java even if called from within a non-static member function.
Is there a way?
Every class inherits the instance method Object#getClass(). Invoke that to get your instance's corresponding Class object.
I don't know why you would do this inside Foo as Foo already knows its static fields and you'd have access to them at compile time directly.
Non-statically, you can use this.getClass() to get the current class, as #sotirios-delimanolis mentioned.
Statically, you can do this, though it is a bit ugly:
public static Class<?> getCurrentClassStatic() {
try {
return Class.forName(new Throwable().getStackTrace()[0].getClassName());
} catch (ClassNotFoundException e) {
return null; //Shouldn't happen...
}
}
Consider a class OriginalClass that might or might not be available on runtime. OriginalClass has a method doSomething which should be executed if its class is available.
A way of solving this is creating a class that also has a doSomething method that calls the OriginalClass.doSomething using reflection. Something like this:
public class CompatibilityClass {
private static Method originalClass_doSomething = null;
static {
initCompatibility();
};
private static void initCompatibility() {
try {
originalClass_doSomething = Class.forName("originalClass").getMethod("doSomething", new Class[] {});
} catch (NoSuchMethodException nsme) {
} catch (SecurityException se) {
} catch (ClassNotFoundException cnfe) {}
}
public static void doSomething() {
if (originalClass_doSomething != null) {
try {
originalClass_doSomething.invoke(null, new Object[]{});
} catch (Exception e) {}
}
}
}
What is the name of the design pattern applied here? I suspect it's either Adapter, Bridge, Facade or Proxy, but I'm not sure which.
I'd say it's the proxy pattern.
You've create a proxy class that wraps the gory reflection stuff and delegates the method call to a different object.
A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.
You pattern is quite similar to something like performing some method call over a network.
Smells like proxy to me. But aren't you better off using Java's default Dynamic Proxy API?
Definition of proxy:
A proxy forces object method calls to
occur indirectly through the proxy
object, which acts as a surrogate or
delegate for the underlying object
being proxied. Proxy objects are
usually declared so that the client
objects have no indication that they
have a proxy object instance.
Simple explanation:
Adapter: when you have two classes (A and B) that are semantically equivalent/similar, but have different interfaces. Adapter implements interface of A but delegates to B or vice-versa so A and B can be used interchangeably
Bridge - typically used with whole inheritance tree (I never used it though)
Facade - hide complexity of one or more classes behind simpler interface
Proxy - same interface as the target object, delegating to it, typically used for lazy loading and decoupling from target.
So your code sample looks like a Proxy.