Create object from class name without reflection - java

I have a main application that uses an external jar with some plugins that I want to call from my main app. Inside my main app I have a list of class names of the corresponding classes inside the external jar file. I need to create the object of those classes at runtime using the class name string. Since in the main app, I don't have the fully qualified name of the class as the packages are defined inside the jar, I cannot load the class and create the object so, I am delegating the object creation to the jar. I pass the name of the class to the jar. The jar has a class that I have access to as it is loaded by the pf4j plugin manager and that class creates the object using reflection and gives it back to my main app.
public Job getJob(String jobClass) {
Job job = null;
Class<?> clazz = null;
try {
clazz = Class.forName("main." + jobClass);
Constructor<?> ctor = clazz.getConstructor();
job = (Job) ctor.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
return job;
}
Using the above function I get the object but is there another way to do this inside the main app without using reflection?

Related

InvalidUseOfMatchersException when using mockito to force a CloneNotSupportedException in a Copy() method being junit tested

I'm trying to access part of a copy method protected by a try catch using mockito while attempting to get 100% coverage in my junit tests. The class that contains the method I want to access implements cloneable making it difficult to throw ClassNotFoundExceptions.
I've tried to force this exception several different ways through mockito's ability to throw exceptions when calling a method but have always come up with an InvalidUseOfMatchersException.
following is the code i need to access and my best attempt at reaching it, respectively
catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
MyClass dict = mock(MyClass.class);
Object obj1 = new Object();
when(MyClass.copy(anyObject())).thenThrow(ClassNotFoundException.class);
dict.copy(obj1);
I expect to reach the cnfe.printStackTrace() line but cannot.
You seem to be mocking a static method, which is actually impossible. According to #Matthias, it would require modifying the class' byte code at runtime.
You must always call when with an instance method call because:
This guarantees that the method will be called on the mock and not on the original class (i.e. MyClass).
This prevents compile-time errors because such non-static methods cannot be referenced from a static context.
Here is the full Java code:
try {
MyClass dict = mock(MyClass.class);
Object obj1 = new Object();
when(dict.copy(anyObject())).thenThrow(ClassNotFoundException.class);
dict.copy(obj1);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
This should output:
Exception in thread "main" java.lang.ClassNotFoundException

Create different Java classes based on runtime config text

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.

Java Reflection with Child Classes

I'm attempting to use Reflections (as provided by org.reflections) to handle some heavy lifting, and so I don't need to manually create an instance for every class in a very long list. However, Reflections isn't targeting the classes in the way I'd expect, which is causing some issue.
My current Reflections code:
Reflections reflections = new Reflections(this.getClass().getPackage().getName() + ".command.defaults");
Set<Class<? extends Command>> commandClasses = reflections.getSubTypesOf(Command.class);
// Iterate through all the detected/found classes
for (Class c : commandClasses) {
// If a class is abstract, ignore it.
if (Modifier.isAbstract(c.getModifiers())) {
continue;
}
// Attempt to create an instance of the class/command whatever.
try {
c.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
// For once, the right thing to do is just ignore the exception.
// If a command is loaded but we can't create an instance or we
// can't access it, just skip. But, we'll at least log it (for now).
ex.printStackTrace();
}
}
Essentially, my program has all commands present in com.example.command.defaults, where they're divided up into a number of sub-packages just for visual grouping. Each command is in its own class, where it extends one of our three abstract classes in com.example.command: PlayerCommand, SimpleCommand, or just Command. PlayerCommand and SimpleCommand also extend Command.
From my understanding, reflections.getSubTypesOf(Command.class) should allow me to target any class that extends Command in any way, but it doesn't seem to be working that way. Using my debugger tool, I've noticed that only a single class (which extends just Command) is actually being read by the system.
How can I make my Reflections code target all classes that extend Command and any classes that extend a class that extends Command?
Acording to the API documentation, getSubTypesOf(Class<T> type)
gets all sub types in hierarchy of a given type but it also stats that this is "depends on SubTypesScanner configured".
The issue is that not all classes are loaded and known by the class loader in advanced and therefor you don't get it in the result list.

Problem with Java Class.forName

I'm trying to use Class.forName to dynamically load a class from a .jar file on the filesystem at runtime. The class I am trying to load implements an interface in another .jar file, so I am using my own URLClassLoader to reference the two .jars.
The code works when it is called not in the context of the web app (I have tested this by copying and pasting the method into a separate program and calling it from main). However, when I run/debug the web app (I'm using NetBeans) the code fails. The newInstance method throws a ClassCastException when I try to cast the instance to the interface specified in my jar_file_dependencies.jar.
Here is the relevant code if this helps:
File gameJar = new File("C:\\file_path\\jar_file.jar");
File gameDependenciesJar = new File("C:\\file_path\\jar_file_dependencies.jar");
URLClassLoader cl = new URLClassLoader(new URL[]
{
gameJar.toURI().toURL(),
gameDependenciesJar.toURI().toURL()
});
Class clazz = Class.forName("MyClass", true, cl);
IMyClass myClass = (IMyClass)clazz.newInstance();
System.out.println(game);
} catch (Exception e)
{
System.out.println(e.getMessage());
}
Any suggestions as to why this code is working in one program and not another would be greatly appreciated.
Many thanks,
Dan
short answer without going into too many of the hairy details: one or both of the gameJar and gameDependenciesJar probably contain a definition of the IMyClass class/interface. the rule of thumb when using child classloaders is that the child classloader should not contain any of the "shared" classes--these should exist only in the parent classloader.
partial explanation: Web app classloaders usually have different delegation policies from normal classloaders. often they prefer the child's class to the parent's. normal classloaders generally prefer the parent's class to the child's. in your web app, you are ending up with 2 separate definitions of the IMyClass class (one def in the parent classloader, one in the child). in your normal app, the IMyClass definition in the child classloader is being ignored, so only one definition gets loaded (in the parent classloader), and everything is happy.
Maybe this will help, (untested):
ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
if (clsLoader == null) {
clsLoader = this.getClass().getClassLoader();
}
URLClassLoader cl = new URLClassLoader(new URL[]
{
gameJar.toURI().toURL(),
gameDependenciesJar.toURI().toURL()
}, clsLoader);
Also, you should pass a full declarative name of the class MyClass instead of just calling it MyClass in Class.forName().
E.g.
Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);

How to use Class.cast() properly?

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?

Categories

Resources