Spring dynamic injection, factory-like pattern

dependency-injection, factory, factory-pattern, java, spring

Solution

If you want some member of your class to be dynamically initialized\populated on every call to the corresponding getter, you can try the Lookup Method Injection. Read pp. 3.3.4.1 here.

So even if the class that contains the dynamic member was created in `scope=singletone` (the default for spring bean container) every time you will accessthe field that has a lookup method assigned, you will get an appropriate object according to the business logic implemented inside the lookup method. In your case the list is an interface so you can easily implement the validation inside your lookup method and return a validated list.

Edit:

I found better example in Spring documentation - I think it is very clear. Take a look at "3.4.6.1 Lookup method injection"

When you configure the `Main` class assign a lookup method to its `List` member - it will be called whenever you need a new instance of the `List` bean.

Good luck!

Problem

A continuation from Dependency injection, delayed injection praxis. I have the Main class: ``` package test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; import java.util.List; import java.util.Scanner; @Component public class Main { @Autowired private StringValidator stringValidator; @Autowired private StringService stringService; @Autowired private ValidationService validationService; public void main() { scanKeyboardCreateLists(); stringValidator.validate(); final List<String> validatedList = stringValidator.getValidatedList(); for (String currentValid : validatedList) { System.out.println(currentValid); } } private void scanKeyboardCreateLists() { //Let's presume the user interacts with the GUI, dynamically changing the object graph... //Needless to say, this is past container initialization... Scanner scanner = new Scanner(System.in); int choice = scanner.nextInt(); //Delayed creation, dynamic if (choice == 0) { stringService.createList(); validationService.createList(); } else { stringService.createSecondList(); validationService.createSecondList(); } } public static void main(String[] args) { ApplicationContext container = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml"); container.getBean(Main.class).main(); } } ``` And the object graph is dynamically created, depending on the user interaction. I solved the application coupling, allowing me to test this very simply. Also, since the lists are maintained by the container, the dynamic nature of this application(and every other) is irrelevant, since they can be requested any time the application needs them, maintaining their elements. The rest of the code is here: ``` package test; import java.util.List; public interface Stringable { List<String> getStringList(); } package test; import org.springframework.stereotype.Component; import java.util.ArrayList; @Component public class StringList extends ArrayList<String> { } package test; import org.springframework.stereotype.Component; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @Component public class StringService implements Stringable { private List<String> stringList; @Inject public StringService(final ArrayList<String> stringList) { this.stringList = stringList; } //Simplified public void createList() { stringList.add("FILE1.txt"); stringList.add("FILE1.dat"); stringList.add("FILE1.pdf"); stringList.add("FILE1.rdf"); } public void createSecondList() { stringList.add("FILE2.txt"); stringList.add("FILE2.dat"); stringList.add("FILE3.pdf"); stringList.add("FILE3.rdf"); } @Override public List<String> getStringList() { return stringList; } } package test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component public class StringValidator { private List<String> stringList; private List<String> validationList; private final List<String> validatedList = new ArrayList<String>(); @Autowired public StringValidator(final ArrayList<String> stringList, final ArrayList<String> validationList) { this.stringList = stringList; this.validationList = validationList; } public void validate() { for (String currentString : stringList) { for (String currentValidation : validationList) { if (currentString.equalsIgnoreCase(currentValidation)) { validatedList.add(currentString); } } } } public List<String> getValidatedList() { return validatedList; } } package test; import java.util.List; public interface Validateable { List<String> getValidationList(); } package test; import org.springframework.stereotype.Component; import java.util.ArrayList; @Component public class ValidationList extends ArrayList<String> { } package test; import org.springframework.stereotype.Component; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @Component public class ValidationService implements Validateable { private List<String> validationList; @Inject public ValidationService(final ArrayList<String> validationList) { this.validationList = validationList; } //Simplified... public void createList() { validationList.add("FILE1.txt"); validationList.add("FILE2.txt"); validationList.add("FILE3.txt"); validationList.add("FILE4.txt"); } public void createSecondList() { validationList.add("FILE5.txt"); validationList.add("FILE6.txt"); validationList.add("FILE7.txt"); validationList.add("FILE8.txt"); } @Override public List<String> getValidationList() { return validationList; } } ``` Does anyone know how would I solve the method call createList() or createSecondList() - without using the constructor which pretty much forces the design. I was thinking of a factory, but a factory for every class in a project of a bigger magnitude doesn't seem like a good idea. Something like: ``` <bean ... factory-method="..." depends-on="..." lazy-init="..."/> ``` And in the factory method instantiate the class and call the method createList(). Or call it like this, from some method - which again looks bad, forcing the method to have the responsibility to instantiate the object graph. The picture of the runtime dependencies that I want to resolve in runtime is bellow: Is there some other way I could use the container to achive dynamic lazy initalization depending on the user interaction? Thank you.

Original source

Related problems