1

This is a little bit of a complicated issue, but I'll do my best to explain it understandably.

To start, consider the following classes.

public abstract class Invokable {
    private String name;

    protected Invokable(String name) { ... }

    public String getName() { ... }

    public abstract void invoke();
}

public class PrintInvokable extends Invokable {
    public PrintInvokable() {
        super("print");
    }

    @Override
    public void invoke() { ... }
}

Another class, InvokerDispatcher, handles events from a messaging application and calls Invokable#invoke on an instance of the appropriate implementation based on the name field. This is all done reflectively so as to be able to scan the classpath for all the valid Invokable implementations and dynamically load them at runtime.

The issue here is that I can only access name via instance, so I have to instantiate a copy of every Invokable in order to check its name against the message content. My solution right now is to keep a list of pre-instantiated copies of each implementation in a separate class, then call a method that fetches and replaces an instance from the list by name.

I'd like to be able to access name statically instead, but I can't come up with a way to do so enforcably. Having a static abstract getName() in Invokable would be the easiest way to do it, but unfortunately Java doesn't support it. Any ideas?

My abstraction of this issue probably isn't the best, so here's my actual source code. The relevant classes are in the command package.

cbryant02
  • 583
  • 4
  • 16
  • [This question](https://stackoverflow.com/questions/4730036/java-static-abstract-again-best-practice-how-to-work-around/13646294) offers a solution to the issue that involves keeping a static instance of a container class for the implementation's info, but it's still not enforceable and I can't up-cast the subclasses without losing access to the info. – cbryant02 Jul 03 '19 at 23:47
  • I'm not sure what you mean by "enforceable". How about a static Map that is populated at startup? Through the class object you can reflectively access constructors, fields, etc. – President James K. Polk Jul 03 '19 at 23:57
  • Why _can't_ you just instantiate them all and keep a list of them? – chrylis -cautiouslyoptimistic- Jul 04 '19 at 00:22
  • @James K Polk By "enforceable" I mean that I want to contractually require that subclasses of `Invokable` will populate the `name` field. I don't think a Map would be too much better than my current solution, especially considering that I'd still have to instantiate each class at least once to get the corresponding key (i.e. `name`) – cbryant02 Jul 04 '19 at 00:27
  • @chrylis That's exactly what I'm doing, funnily enough. The separate class I mentioned in the 3rd paragraph of the question populates a `List` with an instance of each `Invokable` implementation found on the classpath. A method is exposed by the class that finds an `Invokable` by name, removes an instance of it from the list, replaces it with a new instance, then returns the removed `Invokable`. It works fine, but I'd just prefer to expose `name` and whatever other fields statically so I don't have to keep an instance of every implementation in memory all the time. – cbryant02 Jul 04 '19 at 00:32
  • 1
    Are you using spring (or similar injection)? If so, you could make each instance a named component and grab the one you need by name, letting spring handle everything. If not, you should :) – Bohemian Jul 04 '19 at 01:58
  • @Bohemian I actually am using Spring, and had no idea it could do that. Loving this framework more and more as time goes on. I'll give that a shot when I'm back at my workstation. – cbryant02 Jul 04 '19 at 02:00
  • I figure that's still not necessarily a contractual solution, but depending on how Spring makes it work, I might like it better. – cbryant02 Jul 04 '19 at 02:10

0 Answers0