Is there a way to instantiate all children of an abstract class dynamically?
What I have currently is similar to this:
public class CommandHandler {
private Command info = new Info();
private Command prefix = new Prefix();
private Command roll = new Roll();
private Command coin = new Coin();
private Command invite = new Invite();
private Command quit = new Quit();
private Command restart = new Restart();
}
With the abstract parent class being something like this:
public abstract class Command {
protected String name;
protected String arguments;
protected abstract void execute();
}
But what if I want to instantiate all classes that extend Command without typing them all out individually and adding to the list every time I add a command?
And if I can instantiate them dynamically, can I also manipulate them dynamically? i.e. add each class to a list once it has been instantiated.
Or is there a better design to use that accomplishes what I want in a simpler way?
EDIT: #Ash's solution works perfectly in an IDE, but not when using a jar. All you have to do to make it work in both is change
classPathList.addAll(ClasspathHelper.forClassLoader());
to
classPathList.addAll(ClasspathHelper.forJavaClassPath());
Hope it helps someone!
If you use maven (if not, you should :p), add the following dependency :
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
Then you can list the class you want with the following code (assuming you have a constructor with no parameters) :
public class Loader {
public static void main(String[] args) {
try {
Set<URL> classPathList = new HashSet<URL>();
classPathList.addAll(ClasspathHelper.forClassLoader());
Set<Class<? extends Command>> result = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner()).setUrls(classPathList)).getSubTypesOf(Command.class);
List<Command> commands = new ArrayList<Command>();
for (Class<? extends Command> c : result) {
System.out.println(c.getSimpleName());
commands.add(c.newInstance());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
I'm coding something like cmd in java, so I made a few commands like (hello world), , etc. All the commands are classes that implement the interface (I named it as "API"), but to identify which command is written, I use the "if" expression, so to add the new command (class), I have to write this expression every time, for instance:
if (command.equals("print")){return new Print();}
Well, that's the question, how can I write an expression once to make java identify a new command (class), no matter how much I add?
Thanks in advance;
That's the code:
This interface helps the program identify which command is written:
public interface UI {
API get();
Function<String, UI> check = command -> {
if (command.equals("print")){return new Print();}
if (command.equals("change")){return new Change();}
if (command.equals("exit")){return new Exit();}
return new NotFound();
};
static UI of(String command){
return check.apply(command);
}
}
An example of a class:
public class Print extends Backend implements API, UI{
#Override
public boolean command() {
System.out.println(string);
return true;
}
#Override
public API get() {
return new Print();
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean run = true;
while (run) {
System.out.print("Java> ");
//UI
UI command = UI.of(scanner.next());
API com = command.get();
run = com.command();
}
}
}
Please forgive my Java syntax as I am a Java beginner.
I have 3 classes Main, Tool, ToolResultCallback.
class Main {
private DataList dl;
public doSomething() {
Tool t = new Tool();
ToolResultCallback TRC = new ToolResultCallback();
t.startSomething(TRC);
}
}
// in separate file
class Tool {
public void startSomething(ToolResultCallback TRC) {
}
}
// in separate file
class ToolResultCallback extends AbstractTRC {
#Override
public onEvent(SomeData d) {
// how to populate DataList of Main?
}
}
How do I populate DataList dl from callback function in another class/ file?
Pass dl to the ToolResultCallback constructor, and store it in a field.
Thanks #tgdavies
I have a library which parse URLs and extract some data. There is one class per URL. To know which class should handle the URL provided by the user, I have the code below.
public class HostExtractorFactory {
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
switch (host) {
case HostExtractorABC.HOST_NAME:
return HostExtractorAbc.getInstance();
case HostExtractorDEF.HOST_NAME:
return HostExtractorDef.getInstance();
case HostExtractorGHI.HOST_NAME:
return HostExtractorGhi.getInstance();
default:
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
}
The problem is users are requesting more URL to be parsed, which means my switch statement is growing. Every time someone comes up with a parser, I have to modify my code to include it.
To end this, I've decided to create a map and expose it to them, so that when their class is written, they can register themselves to the factory, by providing the host name, and the extractor to the factory. Below is the factory with this idea implemented.
public class HostExtractorFactory {
private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>();
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
if(EXTRACTOR_MAPPING.containsKey(host)) {
return EXTRACTOR_MAPPING.get(host);
} else {
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
public static void register(String hostname, HostExtractor extractor) {
if(StringUtils.isBlank(hostname) == false && extractor != null) {
EXTRACTOR_MAPPING.put(hostname, extractor);
}
}
}
And the user would use it that way:
public class HostExtractorABC extends HostExtractor {
public final static String HOST_NAME = "www.abc.com";
private static class HostPageExtractorLoader {
private static final HostExtractorABC INSTANCE = new HostExtractorABC();
}
private HostExtractorABC() {
if (HostPageExtractorLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
HostExtractorFactory.register(HOST_NAME, this);
}
public static HostExtractorABC getInstance() {
return HostPageExtractorLoader.INSTANCE;
}
...
}
I was patting my own back when I realized this will never work: the user classes are not loaded when I receive the URL, only the factory, which means their constructor never runs, and the map is always empty. So I am back to the drawing board, but would like some ideas around getting this to work or another approach to get rid of this pesky switch statement.
S
Another option is to use the Service Loader approach.
Having your implementers add something like the following in ./resources/META-INF/services/your.package.HostExtractor:
their.package1.HostExtractorABC
their.package2.HostExtractorDEF
their.package3.HostExtractorGHI
...
Then in your code, you can have something like:
HostExtractorFactory() {
final ServiceLoader<HostExtractor> loader
= ServiceLoader.load(your.package.HostExtractor.class);
for (final HostExtractor registeredExtractor : loader) {
// TODO - Perform pre-processing which is required.
// Add to Map? Extract some information and store? Etc.
}
}
I would advice for you to learn about dependency injection (I love spring implementation). You will then be able to write an interface like
public interface HostExtractorHandler {
public String getName();
public HostExtractor getInstance();
}
Than your code can "ask" for all classes that implements this interface, you then would be able to build your map in the initialization phase of your class.
I would use the Reflections library to locate the parsers. They all appear to derive from the HostExtractor class, so use the library to locate all subtypes:
Reflections reflections = new Reflections("base.package");
Set<Class<? extends HostExtractor>> extractorTypes =
reflections.getSubTypesOf(HostExtractor.class);
Use the results to create the instances in your factory:
for (Class<? extends HostExtractor> c : extractorTypes) {
HostExtractor he = c.newInstance();
EXTRACTOR_MAPPING.put(he.getHostName(), he);
}
I made up the getHostName method, but it should be trivial to add to the HostExtractor base class.
I have the class which have the variable and method as below:
public class ProjectsPage extends State {
private Container<Project> newcontainer;
public ProjectsPage(Kick kick) {
super(kick);
}
public void setItem() {
newcontainer = ??? kick.proj
}
}
Object kick has variable proj with the same type as newcontainer:
public class Kick {
public Container<Project> proj = new ContainerDB();
//here I add content to proj
}
Now I want to initialise newcontainer with the same constructor ContainerDB as kick.proj. In another words make an empty kick.proj. Something like this (since kick.proj and newcontainer uses the same interface):
newcontainer = new ContainerDB();
But the problem is class kick can change classes for proj.Like
public class Kick {
public Container<Project> proj = new ContainerDBSQL();
//here I add content to proj
}
I need it (I mean initialise with the same type) since newcontainer later on should contain only specific entries from kick.proj. Not all entries.
How to do it?
try instantiating the object with this:
newContainer = kick.proj.getClass().newInstance();
Ok, so i have a kind of command manager for one of my programs.
Theres a abstract baceclass called Command which is, really simple
public abstract class Command {
protected String commandheader;
protected int requiredlevel;
protected Random rand;
public Command(RANK rank,String command)
{
commandheader = command;
requiredlevel = rank.level;
}
}
Then in each of the classes that inherit this, i just so some oop magic.
public class MyCommand extends Command {
public MyCommand()
{
super(RANK.PLAYER,"blablabla");
}
}
Then i also have a command helper class, which keeps each of these commands in a list so i can easily find if the command, is valid when i pass it in, aswell as get a lsit of all commands that are avalable.
public class CommandHelper {
public enum RANK{
PLAYER(0);
public int level;
private RANK(int i)
{
level = i;
}
}
static List<Command> commandlist;
private static void initTheCommands()
{
//Add the commands to the list here.
commandlist.add(new MyCommand());
}
//Called by my main class
public static void Init()
{
if(commandlist == null)
{
//Were safe to initalise the stuff brah.
commandlist = new ArrayList<Command>();
initTheCommands();
for(Command cmd : commandlist)
{
System.out.println("Loaded command: " + cmd.commandheader);
}
System.out.println("[INFO] Initalised the command helper");
}
else
{
System.out.println("[INFO] Command list is already populated.");
}
}
}
As of right now, this system works completely fine. But it has a flaw, for each command i or the other editors add, we have to manually add it to the list, and that seems tedious and can lead to problems as we sync files. So i was wondering, is there any way i can add each command to the list without having to manually put it there? Perhaps annotate my method, or something to just add it to the list? I seen something about reflection, but i don't think that's what i want exactly although im not sure about it. Iv never used nor made annotations before so im not sure weather or not this is plausible.
If thats what you really want to do you can do something like this...
Declare your annotation
#Target (ElementType.TYPE)
#Retention (RetentionPolicy.RUNTIME)
public #interface CommandAnnotation {
}
Annotate your commands
#CommandAnnotation
public class MyCommand {
Then check for them something like this
...
import org.reflections.Reflections;
...
public void loadCommands() {
Reflections reflections = new Reflections("com.my.package");
Set<Class<?>> allClasses = reflections.getSubTypesOf(Command.class);
for (Class<?> outerClazz : allClasses) {
CommandAnnotation annotation = outerClazz.getAnnotation(CommandAnnotation.class);
if (annotation == null)
continue;