Java Guice Provider - java

I have a small problem which I can't figure out to save my life.
Basically I need to register classes anytime dynamically using guice and then loop through them all.
Lets say this is my class to register Strategies but these strategies can be added anytime through the application running.
// Strategy registration may happen anytime, this is just an example
strategyManager.register(ExampleStrategy1.class);
strategyManager.register(ExampleStrategy2.class);
StrategyImpl class
public class StrategyImpl implements Strategy {
#Override
public void register(Class<? extends StrategyDispatcher> strat) {
//Add this class into provider or create an instance for it and add it into guice but how?
}
#Override
public void dispatchStrategy() {
//Find all strategies and execute them
}
}
I've tried using a Provider but have no idea how i'd add the registered class into the provider and retrieve them all?
#Override
protected void configure() {
bind(Strategy.class).toProvider(StrategyProvider.class);
}
My provider class always gets the same instance
public class StrategyProvider implements Provider<StrategyDispatcher> {
public LogManager get() {
return new StrategyDispatcherImpl();
}
}
The strategies that I add extend the StrategyDispatcherImpl class so i could cast them?
I need to add multiple binds to a same instance but it needs to be done dynamically and not using the bind method in configure but another way then be able to find all these strategies and execute them.

If you truly need it to happen at "any time" during the application life cycle then Guice then I think you will need some sort of Guice-aware Factory. I.e.
public class TestStuff {
#Test
public void testDynamicCreation() {
Injector injector = Guice.createInjector();
StrategyManager manager = injector.getInstance(StrategyManager.class);
Hello hello = injector.getInstance(Hello.class);
manager.doStuff();
assertThat(hello.helloCalled, is(false));
manager.register(Hello.class); // DYNAMIC!!
manager.doStuff();
assertThat(hello.helloCalled, is(true));
}
}
interface Strategy {
void doStuff();
}
#Singleton
class Hello implements Strategy {
boolean helloCalled = false;
public void doStuff() {
helloCalled = true;
}
}
class StrategyManager {
private final Collection<Strategy> strategies = new ArrayList<>();
private final StrategyFactory factory;
#Inject
StrategyManager(StrategyFactory factory) {
this.factory = factory;
}
public void register(Class<? extends Strategy> strat) {
strategies.add(factory.create(strat));
}
public void doStuff() {
for (Strategy s : strategies) {
s.doStuff();
}
}
}
class StrategyFactory {
private final Injector injector;
#Inject
StrategyFactory(Injector injector) {
this.injector = injector;
}
public Strategy create(Class<? extends Strategy> clazz) {
return injector.getInstance(clazz);
}
}
If it is not "dynamic" after the initialization phase then you are after the "multibinder" I think.

Related

How to implement factory pattern better with spring boot native support?

Best way to implement factory pattern in Spring boot.
I've an interface and multiple implementations of it. During a request, I need to return the bean based on an input string.
There are multiple ways I can do it.. But whats the best way?
interface vehicle {
void drive();
string getVehicleName();
}
#Component
public class Car implements vehicle {
private static string prop = "car";
#Override
string getVehicleName() { return prop;}
#Override
void drive() {}
}
#Component
public class Bike implements vehicle {
private static string prop = "bike";
#Override
string getVehicleName() { return prop;}
#Override
void drive() {}
}
#Service
public class VehicleFactory {
#Autowired
private List<vehicle> vehicles;
private static final HashMap<String, vehicle> requestVehicleMap = new HashMap<>();
#PostConstruct
public void initVehicleFactory() {
for(vehicle vehicle : vehicles) {
requestVehicleMap.put(vehicle.getVehicleName(), request);
}
}
public static vehicle getVehicleImpl(String vehicleName) {
return requestVehicleMap.get(vehicleName);
}
}
This does give me correct class.
Also there is "qualifier" that can be used as Implementing custom factory pattern in Spring.
But is there better approach?
Interface and it's Implementation are good, I would just change the Factory class alone because you already I got the List of Implementation then Why again to initialise it in a Map
I will also comment the suggestions in the code
VehicleFactory
#Service
public class VehicleFactory {
#Autowired
private List<Vehicle> vehicles;
public Vehicle getVehicleImpl(String vehicleName) { // You have already declared as #Service then why use static
return vehicles.stream()
.filter(vehicle -> vehicle.getVehicleName().equalsIgnoreCase(vehicleName)) // This will filter the Impl you needed from others
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format(" Invlaid Vehicle Name - %s", vehicleName))); // Incase Impl is not found it should throw an error or handle in some other ways
}
}
So give it a try

Guice database factory

I have an Java project and I need to implement Guice.
I have a modular project, so I can easily switch between databases. To do that I have I DBConnection factory that looks like this:
public abstract class DBConnectionFactory {
// List of DAO types supported by the factory
public static final int MYSQL = 1;
public static final int ORACLE = 2;
public abstract FilterDAO getFilterDAO();
public abstract PhotoDAO getPhotoDAO();
public abstract SetDAO getSetDAO();
public static DBConnectionFactory getDBConnectionFactory(int whichFactory) {
switch (whichFactory) {
case MYSQL:
return new MySQLFactory();
case ORACLE:
return new OracleFactory();
default:
return null;
}
}
}
The factory returns an connection which looks for MySQL like this:
public class MySQLFactory extends DBConnectionFactory {
public static final String DRIVER= "com.mysql.jdbc.Driver";
public static final String DBURL= "jdbcurl";
private static final String PASSWORD = "password";
private static final String USERNAME = "username";
// method to create MySQL connection
public static Connection createConnection() {
try {
// This will load the MySQL driver, each DB has its own driver
Class.forName(DRIVER);
Connection connect = DriverManager.getConnection(DBURL, USERNAME, PASSWORD);
return connect;
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public FilterDAO getFilterDAO() { return new MySQLFilterDAO(); }
public PhotoDAO getPhotoDAO() {
return new MySQLPhotoDAO();
}
public SetDAO getSetDAO() {
return new MySQLSetDAO();
}
}
In my ServletController I have this code to establish the connection:
// Create a DAO
private DBConnectionFactory MySQLFactory = DBConnectionFactory.getDBConnectionFactory(DBConnectionFactory.MYSQL);
#Override
public void init(){
photoDAO = MySQLFactory.getPhotoDAO();
}
I'm trying to get rid of the factory and use Guice, but I don't know where to start. Thanks in advance!
To expand on my comment and provide a better example. This assumes play framework but the principle should be quite the same.
The first thing you need to do when using Guice is bind implementations to interfaces. For instance I need a FlagDAO.
public interface FlagDAO {
public Flag getByName(String name) throws FlagNotFoundException;
}
Now I have a couple of implementations of it of which I won't show the code entirely:
// This one is used in production/development
public class FlagDAOEbean implements FlagDAO {
// Some code
}
// This one is used for testing
public class FlagDAOInMemory implements FlagDAO { {
// Some code
}
To use the FlagDAO in some other service. This SomethingUsingFlagDAO class must also be constructed through Guice so the proper values are injected
public class SomethingUsingFlagDAO {
#Inject
public SomethingUsingFlagDAO(FlagDAO flagDAO) {
}
}
Now play framework uses modules to bind certain stuff on application startup. I have disabled this module in testing but the code is run in development and production environment.
public class DAOModule extends AbstractModule {
public void configure() {
bind(FlagDAO.class).to(FlagDAOEbean.class);
bind(SomethingUsingFlagDAOInterface.class).to(SomethingUsingFlagDAO.class);
}
}
I have this code on my testcases. Note that the only thing that is actually different is which FlagDAO implementation is bound to Guice:
public class FlagsTest extends WithApplication {
private SomethingUsingFlagDAO something;
#Before
public void setUp() {
Injector injector = this.provideApplication().injector();
this.something = injector.instanceOf(SomethingUsingFlagDAO.class);
}
#Override
protected Application provideApplication() {
Application application = new GuiceApplicationBuilder()
.in(new Environment(new File("./"), this.getClass().getClassLoader(), Mode.TEST))
.bindings(bind(FlagDAO.class).to(FlagDAOInMemory.class))
.bindings(bind(SomethingUsingFlagDAOInterface.class).to(SomethingUsingFlagDAO.class))
.build();
return application;
}
}
So depending on whether we are in a development/production/testing environment a different DAO implementation is used without actually changing how anything works. No if (application.isTesting()) checks where they should not be.
In your case you could imagine a FlagDAOOracle alongside the FlagDOAEbean and FlagDAOInMemory which is bound like so:
public class DAOModule extends AbstractModule {
public void configure() {
if(weNeedOracle) {
bind(FlagDAO.class).to(FlagDAOOracle.class);
} else {
bind(FlagDAO.class).to(FlagDAOMysql.class);
}
}
}

Guice: injecting factory-generated instances properly

I'm using Guice 3.0 on a Groovy project and am running into bizarre/unexpected injection behaviors. My main/bootstrapping class:
class WidgetServicePerfTester {
#Inject
WidgetGenerator widgetGenerator
static main(args) {
Injector injector = Guice.createInjector(new WidgetServicePerfTesterModule())
WidgetServicePerfTester perfTester = injector.getInstance(WidgetServicePerfTester)
perfTester.run()
}
void run() {
List<Widget> widgets = widgetGenerator.generateWidgets()
widgets.each {
it.doStuff()
}
}
}
My POJO:
class Widget extends Thingy {
WidgetClient widgetClient
int numFoos
#Override
void doStuff() {
widgetClient.doSomethingOnServer()
}
}
My POJO generators (API + impl):
interface WidgetGenerator {
List<Widget> generateWidgets()
}
class SimpleWidgetGenerator implements WidgetGenerator {
#Inject
WidgetClient widgetClient
int numWidgets
SimpleWidgetGenerator() {
super()
}
SimpleWidgetGenerator(int numWidgets) {
super()
this.numWidgets = numWidgets
}
#Override
List<Widget> generateWidgets() {
List<Widget> widgets = []
Widget firstWidget = new Widget(widgetClient: widgetClient, numFoos: getRandomNumber())
widgets.add(firstWidget)
// Code that populates the rest of 'widgets' with 'numWidgets' number of Widgets.
}
}
My Guice module:
class WidgetServicePerfTesterModule extends AbstractModule {
#Override
protected void configure() {
bind(WidgetClient).to(SimpleWidgetClient)
}
#Provides
public WidgetGenerator provideSimpleWidgetGenerator() {
new SimpleWidgetGenerator(50)
}
}
When I run this code I get null pointer exceptions because the WidgetClient injected into each Widget is NULL. Why and what's the fix?
The whole problem begins here in WidgetServicePerfTesterModule class, in the following block of code:
#Provides
public WidgetGenerator provideSimpleWidgetGenerator() {
new SimpleWidgetGenerator(50)
}
An instance of SimpleWidgetGenerator is created using this constructor:
SimpleWidgetGenerator(int numWidgets) {
super()
this.numWidgets = numWidgets
}
and since this object is created manually injecting WidgetClient into SimpleWidgetGenerator will not work - it's null and it's explainable.
To fix the problem guice-assistedinject should be used and factory for Widgets should be created. Here you can find refactored project using the mentioned extensions. Everything works fine.
Is that clear now?

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.
I would suggest the following approach:
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.)
Inject all of the identified Task objects into your factory:
#Autowired
private Set<Task> scannedTasks;
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.
I got into similar kind of problem to solve, what I really did is, It may be helpful.
Define Tasks Enum like.
public enum Tasks {
Task1(SubTasks.values());
Tasks(PagesEnumI[] pages) {
this.pages = pages;
}
PagesEnumI[] pages;
// define setter and getter
}
Defined Subtask like
public interface PagesEnumI {
String getName();
String getUrl();
}
public enum SubTasks implements PagesEnumI {
Home("home_url");
SubTasks(String url) {
this.url = url;
}
private String url;
#Override
public String getUrl() {
return url;
}
#Override
public String getName() {
return this.name();
}
}
Defined Service to call per SubTasks enum like
public interface PageI {
void process();
Sites getTaskName();
PagesEnumI getSubTaskName();
}
#Component
public class Home implements PageI {
// function per SubTask to process
#Override
public void process() {}
// to get the information about Main Task
#Override
public Tasks getTaskName() {
return Tasks.Task1;
}
// to get the information about Sub Task
#Override
public PagesEnumI getSubTaskName() {
return Task1.Home;
}
}
Define a factory like...
#Component
public class PageFactory {
Set<PageI> pages;
// HashMap for keeping objects into
private static HashMap<String, PageI> pagesFactory = new HashMap<>();
#Autowired
public void setPages(Set<PageI> pages) {
this.pages = pages;
}
// construct key by
private static String constructKey(Tasks taks, PagesEnumI page) {
return task.name() + "__" + page.getName();
}
// PostConstruct means after construct class object this method should get run
// iterating over all pages and storing into Map
#PostConstruct
private void postConstruct() {
for (PageI pageI : pages) {
pagesFactory.put(constructKey(pageI.getTaskName(), pageI.getSubTaskName()), pageI);
}
}
// getting object from factory
public PageI getPageObject(Tasks task, PagesEnumI page) {
return pagesFactory.get(constructKey(task, page));
}
}
Till now we have registered our enum(Tasks and SunTasks) and their service(With getter of Tasks and SubTasks), Now defining a factory to call service process method.
#SpringBootApplication
public class Application implements CommandLineRunner {
PageFactory factory;
#Autowired
public void setFactory(PageFactory factory) {
this.factory = factory;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
// for each task we might have different sub task
Arrays.stream(Tasks.values()).forEach(
task -> {
// for each and subtask of a task need to perform process
for (PagesEnumI page : task.getPages()) {
PageI pageI = factory.getPageObject(task, page);
pageI.process();
}
}
);
}
}
This is not exact similar problem, way to solve it may be similar. So I thought this might be helpful to put it here. Please don't by putting name, just trying to understand concept. If anyone have more inputs, please share.
Let Task tell the factory which TaskType it supports.
It can be done using a plain old Java method, no Spring annotations required.
public interface Task {
void process();
TaskType supportedType();
}
#Component
public class VerifyXTask implements Task {
#Override
public void process() {
}
#Override
public TaskType supportedType() {
return TaskType.VERIFY_X_TASK;
}
}
#Component
public class TaskFactory {
private Map<TaskType, Task> tasks;
public TaskFactory(List<Task> tasks) {
this.tasks = tasks.stream()
.collect(Collectors.toMap(Task::supportedType, Function.identity()));
}
public Task getTask(TaskType type) {
return tasks.get(type);
}
}

How to implement and test mapbinding correctly with Guice and Play framework

I just started using Guice and Play so I guess this is a long but basic question. I checked the guide here: http://eng.42go.com/play-framework-dependency-injection-guice/ but I don't know why my code fails.
First I have a global injector:
public class GlobalInjector {
private static Injector guiceInjector;
private static List<AbstractModule> modules = new ArrayList<AbstractModule>();
public static Injector getInjector() {
return guiceInjector;
}
public static loadModules() {
guiceInjector = Guice.createInjector(modules);
}
public static addModule(AbstractModule module) {
modules.add(module);
}
}
Also I have added Guice to Play by extending the GlobalSettings class (also modified application.global)
public class GuiceExtendedSettings extends GlobalSettings {
#Override
public void onStart(Application app) {
GlobalInjector.loadModules();
}
#Override
public <A> A getControllerInstance(Class<A> controllerClass) {
return GlobalInjector.getInjector().getInstance(controllerClass);
}
}
Then I have my test module acting as a plugin in Play (some required methods are omitted as they do nothing in this piece):
public class TestModule extends AbstractModule implements Plugin {
#Override
public void configure() {
// Worker is a simple class
Worker worker = new SimpleWorker();
MapBinder<String, Worker> mapBinder = MapBinder.newMapBinder(binder(), String.class, Worker.class);
mapBinder.addBinding(worker.getName()).toInstance(worker);
}
#Override
public void onStart() {
GlobalInjector.addModule(this);
}
}
Worker is a simple interface:
public interface Worker {
public String getName();
public String getResult();
}
SimpleWorker:
public class SimpleWorker implements Worker {
public String getName() {
return "SimpleWorker";
}
public String getResult() {
return "works";
}
}
And here is the code piece showing the controller logic: nothing but just print all worker results in the map injected
public class TestController extends Controller {
#Inject
Map<String, Worker> workers;
public Result showWorkers() {
StringBuilder sb = new StringBuilder();
for (Worker worker : workers) {
sb.append(worker.getName() + ": " + worker.getResult() + "</br>");
}
return ok(sb.toString()).as("text/html");
}
}
OK. To make this work, I put the following line in play.plugins:
100:test.TestModule
My idea is:
Play loads the plugin (TestModule) -> TestModule adds itself to the GlobalInjector -> GlobalInjector creates Guice injector -> Guice injects the map to the controller
However the result was
Guice didn't inject the map. The map is still null.
Also how should I test it? (i.e. how can I inject different workers to that map? I hard-coded that part in the above code. But I'm looking for a dynamic way by using different modules.)
public class Test {
#Test
public void testInjector() {
running(fakeApplication(), new Runnable() {
public void run() {
// how can I inject using different modules here?
}
});
}
}
You need to use the fakeApplication helper method that allows you to specify both your global settings object and additional plugins. See http://www.playframework.com/documentation/api/2.1.x/java/play/test/Helpers.html#fakeApplication(java.util.Map,%20java.util.List,%20play.GlobalSettings) for more information.
But basically, your test should look something like:
public class Test {
#Test
public void testInjector() {
Map<String, Object> config = new HashMap<String, Object>();
// add any additional config options, e.g. in-memory db
List<String> plugins = new ArrayList<String>();
plugins.add("full.package.name.TestModule");
GlobalSettings global = null;
try {
global = (GlobalSettings) Class.forName("full.package.name.GuiceExtendedSettings").newInstance();
} catch(Exception e) {}
running(fakeApplication(config, plugins, global), new Runnable() {
public void run() {
// do some assertions
}
});
}
}
You also need to make sure that guice instantiates the test controller or the workers map won't be injected.

Categories

Resources