Create different Java classes based on runtime config text - java

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.

Related

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.

Controlling when object is created

Suppose i need to create an object as follows and set some values
FileMetaData fileMeta = fileContainer.getMetaData();
fileMeta.setFileName("file name");
fileMeta.setServer("my box");
fileMeta.setDirectory("/path/to/dir");
fileMeta.setFileType(FileType.PROPERTIES);
I later intend to use this object reference to do something useful.
I'd like to recognize the fact that it is possible for the user of the system to not set some fields, for instance, one may forget to
fileMeta.setDateModified(12345);
Is it somehow possible to guarantee that all (or some specific) fields are set before making the object available?
There is nothing in the language to enforce this (except for having a lone visible constructor that takes all the required parameters), but you can do it idiomatically, with a variation on the builder pattern and some method chaining:
FileMetaData fileMeta = new FileMetaDataBuilder(fileContainer.getMetaData())
.setFileName("file name")
.setServer("my box")
.setDirectory("/path/to/dir")
.setFileType(FileType.PROPERTIES)
.build();
The build() method can ensure that all the required fields are set before calling the appropriate constructor of FileMetaData with all the required parameters.
Use the builder pattern and pass the reference to the builder around. When you're done adding extras on top, call .build and capture the returned instance of FileMetaData.
You could constrain it by not allowing the build to succeed until all of the pre-requisites are set.
Basically I can classify the following 3 ways.
First is based on the class itself. You can add method isReady() to your class. This method will perform all checks and return true or false.
Other way is to use Factory or Builder pattern and probably objects repository. Both factory and builder guarantee to create object in ready state. Repository can be used to "publish" ready objects there, so other code requests objects and receives them in ready state only.
Other approach is to use Wrapper (Decorator) pattern.
interface Foo {
public void foo(); //business method
}
class FooImpl implements Foo {
public void foo(){} // does the work
}
class FooDecorator implmeents Foo {
Foo foo;
public void foo(){
if (isInitialized()) {
foo.foo();
}
throw IllegalStateException("Not initialized");
}
}
This solutions may be implemented using dynamic proxy or using AOP framework as well.

Configuration class - best practice with Guice

Background: I'm using Google Guice and so it's easier to pass through the configuration class but I think this is not the best way.
I have a configuration class which stores some paths:
class Configuration{
String getHomePath();
String getUserPath();
}
Also I have a class "a" which needs the "homepath" and a class "b" which needs the "userpath".
Is it better to pass the configuration class through the constructor of class a and b or only pass through the specific path?
If you're really using Guice correctly all your configuration like this should appear in modules' configure method. So:
Remove the configuration class.
Create annotation classes, probably called HomePath and UserPath.
Where class a uses getHomePath() replace that with a String field member named homePath.
Where class b uses getUserPath() replace that with a String field member named userPath.
Modify the class a and b constructors to be #Inject annotated (should already be) and take in a String parameter, respectively annotated with #HomePath and #UserPath and assign the String field member that injected value.
Create bindings in your module's configure method use .annotatedWith() which define correct values; if they're only available at run time, bind a provider.
E.G.
class a {
private String homePath;
#Inject
public a(#HomePath String homePath) {
this.homePath = homePath;
}
public String tellMeAboutHome() {
return "We live in a nice home called " + homePath;
}
}
class customModule extends AbstractModule {
public static final String userPath = "/home/rafael";
public void configure() {
bind(String.class).annotatedWith(HomePath.class).to("/home/");
bind(String.class).annotatedWith(UserPath.class).to(userPath);
}
}
If creating annotations is too much work for you, use the #Named annotation Guice ships with.
There's no single answer to your question, there are only options to choose from, based on your specific situation.
If you know your Configuration class is going to grow AND if it's likely for your A and B classes will use more from it, then pass the whole Configuration object to their constructors. NB: I know this is against the YAGNI principle but sometimes you may know you're gonna need it ;-)
Otherwise, you can consider using #Named injection of your paths so that you reduce A and B classes dependencies to their minimum, which is a good design practice.
The general rule is code to make the dependency graph (which classes know about or depend on other classes/ interfaces) as simple, regular and fixed as possible.
If not passing the Configuration class makes a or b have zero dependencies on on user-written classes, or is necessary to avoid a dependency loop, then use the individual path strings. Otherwise, if it makes more sense to say 'this class has access to configuration info, in a way that may change in the future', pass the class.
I'd avoid the singleton approach, especially if you already have Guice set up.

Design Pattern Need to remove a series of If.. elses in object initialization

I'm writing an application in which there will be multiple departments and for each department there will be separate processing class.
Each department and department processing is represented by separate class.
so, now main method in java looks more like series of if else ladder.
Is there any way of making it more flexible so that i can add more departments and their processing classes later without modifying the originally written class much ??
I've read about Abstract Factory patterns but is there any other solution than it ??
Create an interface to hide the departments, like "Department". Write your main method like:
main() {
String criteria = ...; // this is how we choose the department to use,
// and you probably don't want to use a String
// but some other, more expressive type
for (Department department : departments) {
if (department.supports(criteria)) {
department.doWhatever();
}
}
}
Then use dependency injection to populate the departments collection. Depending on how you set it up, it could be pure configuration.
The Abstract Factory pattern is probably best suited to the scenario that you described. You will need a heirarchy of Department Processors and a matching heirarchy of Department classes. The Abstract factory will produce a concrete factory for each pair based on some discriminator, process the department for you and return the Department object.
The rest of your application does not need to be aware of the differences in the creation of the department objects since it will use the FActory to get a department simply passing the appropriate discriminator.
Adding a new department will require the new department clas, the processor class and updating the factory logic.
Alternatively, if the structure of the departments are all the same but the processing is different you may consider using something like the Strategy pattern. In this case you have a single Department, but the deccision about processing will be made for the Strategy instead. So the appropriate Strategy is injected into the department and the department's behaviour differs accordingly.
There is a whole web site devoted to the topic. You want to use polymorphism and possibly reflection depending on what you are trying to do.
http://www.antiifcampaign.com/
You can create enum with field for each state. Then create abstract method init() in the enum and implement it for each member.
In your code you can get state from for example properties file and then say State.valueOf(state).init()
Using the "Factory" or the "Abstract Factory" design pattern would be the first step. That would take the object initialization logic out of your main code and isolate it in the factory classes. In that way, your main code would be closed for modification and open for extension (a.k.a. Open Closed Principle). The changes you make will be isolated in the factory classes.
If you want to take this one step further, you may also use reflection. An example would be:
static Object createObject(String className) {
Object object = null;
try {
Class classDefinition = Class.forName(className);
object = classDefinition.newInstance();
} catch (InstantiationException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (ClassNotFoundException e) {
System.out.println(e);
}
return object;
}
With this code, you can simply create an object like this:
public static void main(String[] args) {
NewDepartment dep = (NewDepartment) createObject("yourpackage.NewDepartment");
}
Of course, there is a trade-off when you use reflection. That is up your discretion to use it or not.

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