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);
}
}
}
Related
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.
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);
}
}
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.
Could you guys please help me find where I made a mistake ?
I switched from SimpleBeanEditorDriver to RequestFactoryEditorDriver and my code no longer saves full graph even though with() method is called. But it correctly loads full graph in the constructor.
Could it be caused by circular reference between OrganizationProxy and PersonProxy ? I don't know what else to think :( It worked with SimpleBeanEditorDriver though.
Below is my client code. Let me know if you want me to add sources of proxies to this question (or you can see them here).
public class NewOrderView extends Composite
{
interface Binder extends UiBinder<Widget, NewOrderView> {}
private static Binder uiBinder = GWT.create(Binder.class);
interface Driver extends RequestFactoryEditorDriver<OrganizationProxy, OrganizationEditor> {}
Driver driver = GWT.create(Driver.class);
#UiField
Button save;
#UiField
OrganizationEditor orgEditor;
AdminRequestFactory requestFactory;
AdminRequestFactory.OrderRequestContext requestContext;
OrganizationProxy organization;
public NewOrderView()
{
initWidget(uiBinder.createAndBindUi(this));
requestFactory = createFactory();
requestContext = requestFactory.contextOrder();
driver.initialize(requestFactory, orgEditor);
String[] paths = driver.getPaths();
createFactory().contextOrder().findOrganizationById(1).with(paths).fire(new Receiver<OrganizationProxy>()
{
#Override
public void onSuccess(OrganizationProxy response)
{
if (response == null)
{
organization = requestContext.create(OrganizationProxy.class);
organization.setContactPerson(requestContext.create(PersonProxy.class));
} else
organization = requestContext.edit(response);
driver.edit(organization, requestContext);
}
#Override
public void onFailure(ServerFailure error)
{
createConfirmationDialogBox(error.getMessage()).center();
}
});
}
private static AdminRequestFactory createFactory()
{
AdminRequestFactory factory = GWT.create(AdminRequestFactory.class);
factory.initialize(new SimpleEventBus());
return factory;
}
#UiHandler("save")
void buttonClick(ClickEvent e)
{
e.stopPropagation();
save.setEnabled(false);
try
{
AdminRequestFactory.OrderRequestContext ctx = (AdminRequestFactory.OrderRequestContext) driver.flush();
if (!driver.hasErrors())
{
// Link to each other
PersonProxy contactPerson = organization.getContactPerson();
contactPerson.setOrganization(organization);
String[] paths = driver.getPaths();
ctx.saveOrganization(organization).with(paths).fire(new Receiver<Void>()
{
#Override
public void onSuccess(Void arg0)
{
createConfirmationDialogBox("Saved!").center();
}
#Override
public void onFailure(ServerFailure error)
{
createConfirmationDialogBox(error.getMessage()).center();
}
});
}
} finally
{
save.setEnabled(true);
}
}
}
with() is only used for retrieval of information, so your with() use with a void return type is useless (but harmless).
Whether a full graph is persisted is entirely up to your server-side code, which is intimately bound to your persistence API (JPA, JDO, etc.)
First, check that the Organization object you receive in your save() method on the server-side is correctly populated. If it's not the case, check your Locators (and/or static findXxx methods) ; otherwise, check your save() method's code.
Judging from the code above, I can't see a reason why it wouldn't work.
It took me some time to realize that the problem was the composite id of Person entity.
Below is the code snippet of PojoLocator that is used by my proxy entities.
public class PojoLocator extends Locator<DatastoreObject, Long>
{
#Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, Long id)
{
}
#Override
public Long getId(DatastoreObject domainObject)
{
}
}
In order to fetch child entity from DataStore you need to have id of a parent class. In order to achieve that I switched "ID class" for Locator<> to String which represents textual form of Objectify's Key<> class.
Here is how to looks now:
public class PojoLocator extends Locator<DatastoreObject, String>
{
#Override
public DatastoreObject find(Class<? extends DatastoreObject> clazz, String id)
{
Key<DatastoreObject> key = Key.create(id);
return ofy.load(key);
}
#Override
public String getId(DatastoreObject domainObject)
{
if (domainObject.getId() != null)
{
Key<DatastoreObject> key = ofy.fact().getKey(domainObject);
return key.getString();
} else
return null;
}
}
Please note that your implementation may slightly differ because I'm using Objectify4.
I am having an abstract factory class StudentValidatorFactory which is suppossed to create(based on a specified parameter) various StudentValidator class instances to which a validation map has to be injected (see the code bellow).
public class StudentValidatorFactory{
public static final int JUNIOR_STUDENT_TYPE = 1;
public static final int SENIOR_STUDENT_TYPE = 2;
public StudentValidator createStudentValidator(int studentType) throws StudentValidatorCreationException{
Map<String,ValidationBean> validationMap = readValiationMapFromPersistentOrCachedStorage(studentType);
switch (studentType){
case JUNIOR_STUDENT:
return new JuniorStudentValidator(validationMap);
case SENIOR_STUDENT:
return new SeniorStudentValidator(validationMap);
}
}
}
public interface StudentValidator{
void validate(Student student) throws StudentValidationException;
}
public class JuniorStudentValidator{
private Map<String, ValidationBean> validationMap;
public JuniorStudentValidator(Map<String,ValidationBean> validationMap){
this.validationMap = validationMap;
}
public void validate(Student student) throws StudentValidationException{
// make use of validation map for apply junior student related validations on the student
}
}
public class SeniorStudentValidator{
private Map<String, ValidationBean> validationMap;
public SeniorStudentValidator(Map<String,ValidationBean> validationMap){
this.validationMap = validationMap;
}
public void validate(Student student) throws StudentValidationException{
// make use of validation map for apply senior student related validations on the student
}
}
My question is about the StudentValidatorFactory.createStudentValidator(int studentType) method whether reading the validation map from a persistent storage (based on the student type) should be done within the create method ? Otherwise said, should the factory be aware/dependent about such implementation details?
I'd appreciate if there would be a solution to avoid the switch(studentType) statement when creating the student validator - an idea on top of my head is to have an internally managed map and perform the StudentValidator concrete class instantiation via reflection .
Advantages of using such a technique is that the validators are much easier to be tested (through dependency injection).
Extract the readValiationMapFromPersistentOrCachedStorage(studentType) in a separated service interface StudentValidatorService and inject an instance of the service in the StudentValidatorFactory using a property or constructor argument:
public interface StudentValidatorService {
Map<String,ValidationBean> getValidationMap(int studentType);
}
public class StudentValidatorFactory{
public static final int JUNIOR_STUDENT_TYPE = 1;
public static final int SENIOR_STUDENT_TYPE = 2;
public StudentValidatorFactory(StudentValidatorService studentValidatorService) {
this.studentValidatorService = studentValidatorService;
}
public StudentValidator createStudentValidator(int studentType) throws StudentValidatorCreationException{
Map<String,ValidationBean> validationMap = studentValidatorService.getValidationMap(studentType);
switch (studentType){
case JUNIOR_STUDENT:
return new JuniorStudentValidator(validationMap);
case SENIOR_STUDENT:
return new SeniorStudentValidator(validationMap);
}
}
}
Now you can write an implementation of StudentValidatorService backed by database. Or you can write a mock implementation for testing. The implementation is now decoupled from the usage.
To remove the switch-case, invert it using an enum:
public enum StudentType {
JUNIOR_STUDENT {
public StudentValidator getValidator(Map<String,ValidationBean> validationMap) {
return new JuniorStudentValidator(validationMap);
}
},
SENIOR_STUDENT {
public StudentValidator getValidator(Map<String,ValidationBean> validationMap) {
return new SeniorStudentValidator(validationMap);
}
};
public abstract StudentValidator getValidator(Map<String,ValidationBean> validationMap);
}
public class StudentValidatorFactory{
public StudentValidatorFactory(StudentValidatorService studentValidatorService) {
this.studentValidatorService = studentValidatorService;
}
public StudentValidator createStudentValidator(StudentType studentType) throws StudentValidatorCreationException{
Map<String,ValidationBean> validationMap = studentValidatorService.getValidationMap(studentType);
return studentType.getValidator(validationMap);
}
}