Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring - Dynamic factory based on enum

I have the following classes:

public enum TaskType {

    VERIFY_X_TASK, COMPUTE_Y_TASK, PROCESS_Z_TASK;
}

public interface Task{
    void process();
}

@Component
public class VerifyXTask implements Task{
    // Similar classes for the other types of tasks
    public void process() {
    }
}

@Component
public class TaskFactory{
    private Map<TaskType, Task> tasks;
    public Task getTask(TaskType type){
        return tasks.get(type); // return a singleton with all it's fields injected by the application context
    }
}

class UseTool{
    @Autowired
    private TaskFactory taskFactory;

    public void run(String taskType){
        Task task = taskFactory.getTask(TaskType.valueOf(taskType));
        task.process();
    }
}

What is the most elegant way of injecting the association between TaskType and Task into the factory? Consider that there are almost 100 task types and that these may change quite frequently.

-- Further explanations: I could do in the TaskFactory class smth like:

tasks.put(TaskType.VERIFY_X_TASK, new VerifyTask());
tasks.put(TaskType.COMPUTE_Y_TASK, new ComputeTask());
tasks.put(TaskType.PROCESS_Z_TASK, new ProcessTask());

But this does not inject any properties in the Task object.

like image 320
Alin Stoian Avatar asked Dec 05 '25 05:12

Alin Stoian


1 Answers

I would suggest the following approach:

  1. Define a custom annotation @ImplementsTask that takes a TaskType as a parameter, so that you can write your implementation class like this:

    @Component
    @ImplementsTask(TaskType.VERIFY_X_TASK)
    public class VerifyXTask implements Task {
    ...
    

    (Or you can meta-annotate @Component to avoid having to use it on all the classes.)

  2. Inject all of the identified Task objects into your factory:

    @Autowired
    private Set<Task> scannedTasks;
    
  3. In a @PostConstruct method on the factory, iterate over each of the elements in scannedTasks, reading the annotation value and adding a Map entry (to an EnumMap, of course). You'll need to decide how to deal with duplicate implementations for a given TaskType.

This will require a bit of reflection work in the factory setup, but it means that you can just annotate a Task implementation with the appropriate value and have it scanned in without any additional work by the implementor.

like image 150
chrylis -cautiouslyoptimistic- Avatar answered Dec 06 '25 17:12

chrylis -cautiouslyoptimistic-



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!