I have a method that returns a Map():
private Map<String, Catalog> readCatalogFromXml(String xmlFile) {
// blah blah read XML via DOM
}
However, I need to bind the results of that call to a single instance to be injected into multiple classes. I've been looking over the docs for MapBinder but am confused. I'm probably missing something simple, can anyone assist?
Jason
Just implement a provider in your Module class:
public class ModuleImpl extends AbstractModule {
#Override
protected void configure() {
// bind whatever needed
}
#Singleton
#Provides
Map<String, Catalog> provideMap(#XMLFile String xmlFile) {
// create an instance of your class
return myClass.readCatalogFromXml(xmlFile);
}
}
If you just need the returned Map injected, I would ...
define a subclass "#Singleton public class MyInjectedMap extends HashMap { }"
bind a Provider < MyInjectedMap > to produce instances
Related
I have a class which calls two singleton classes FirstClass and SecondClass as below. Is there a way to access the data computed in FirstClass in the SecondClass. In this case I don't want to make external service call in second class since the first class has already called it. Instead, just use the data (stored in first class function) in the second data function. What are the ways to do it in Spring Framework?
public class CallingFunction() {
List<String> generateData() {
return Lists.newArrayList(new FirstClass(), new SecondClass())
}
#Singleton
public class FirstClass() extends interface {
public String function() {
//operations. This function calls multiple services and stores ouput to hashMap
Map<String, String> hashedData = Maps.newHashMap();
hashedData.put(dataFromAnotherService);
return hashedData.get("abc");
}
}
#Singleton
public class SecondClass() extends interface {
public String function() {
//Use hashedData here instead of invoking the service again.
//Other operations
return "data";
}
}
Pass a reference of FirstClass to SecondClass, either by having Spring do it for you (which is an I.o.C. container is for) or do it explicitly in generateData.
I am using Java 8 with a Play framework. My goal is to inject a map whose keys are enum values and values are implementations of a specific interface.
Here is my enum:
public enum Service {
HTML("html"), TEXT("txt");
private String serviceId;
Service(String serviceId) { this.serviceId = serviceId; }
}
I have Executable interface
public interface Executable { void execute(); }
and two classes that implement it:
public class HtmlWorker implements Executable { ... }
public class TextWorker implements Executable { ... }
I would like to be able to inject Map<Service, Executable> serviceMap so I can have access to a specific implementation using a Service key:
public class Processor {
#Inject
Map<Service, Executable> serviceMap;
public void doStuff() {
Executable htmlService = this.serviceMap.get(Service.HTML);
Executable textService = this.serviceMap.get(Service.TEXT);
// do more stuff
}
}
I added bindings to the module class:
public class AppModule extends AbstractModule {
#Override
protected void configure() {
MapBinder<Service, Executable> serviceBinder = MapBinder
.newMapBinder(binder(), Service.class, Executable.class);
serviceBinder.addBinding(Service.HtmlService).to(HtmlWorker.class);
serviceBinder.addBinding(Service.TextService).to(TextWorker.class);
}
The problem is that serviceMap is never injected and it is always null inside Processor. What am I missing?
According to the official MapBinder documentation the MapBinder.addBinding should take the map's key.
As far as concerning your provided example what about changing AbstractModule's code from:
serviceBinder.addBinding(Service.HtmlService).to(HtmlWorker.class);
serviceBinder.addBinding(Service.TextService).to(TextWorker.class);
to
serviceBinder.addBinding(Service.HTML).to(HtmlWorker.class); // <-- see the enum constant here?
serviceBinder.addBinding(Service.TEXT).to(TextWorker.class);
Anyway I don't know where the class Service.HtmlService in your example comes from since you didn't state it anywhere.
I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.
I have the following scenario:
public interface ServiceClientAdapter {
SomeData getSomeData()
}
#LegacyServiceClientAdapter
public class MyLegacyServiceClientAdapterImpl implements ServiceClientAdapter {
public SomeData getSomeData() {
// implementation
}
}
#NewServiceClientAdapter
public class MyNewServiceClientAdapterImpl implements ServiceClientAdapter {
public SomeData getSomeData() {
// implementation
}
}
public class BusinessLogic {
#Inject
private ServiceClientAdapter serviceClientAdapter;
}
LegacyServiceClientAdapter and NewServiceClientAdapter are custom annotations.
The implementation for the serviceClientAdapter field will be determined at runtime by whether the user has been migrated from the legacy to the new service or not.
What is the best way to accomplish this dependency injection using Google Guice?
Take into account that different BusinessLogic classes will exist, each with their own (different) ServiceClientAdapter-like interface and corresponding legacy and new implementation classes.
Ideally this should be done with a piece of framework code that can be used across all use cases.
I'm going to assume that the result of your LDAP call can be represented as a string, let's say "legacy" or "new". If not, hopefully you should still be able to adapt this example.
In your module, use a MapBinder:
public class BusinessLogicModule {
#Override
protected void configure() {
// create empty map binder
MapBinder<String, ServiceClientAdapter> mapBinder =
MapBinder.newMapBinder(
binder(), String.class, ServiceClientAdapter.class);
// bind different impls, keyed by descriptive strings
mapBinder.addBinding("legacy")
.to(MyLegacyServiceClientAdapterImpl.class);
mapBinder.addBinding("new")
.to(MyNewServiceClientAdapterImpl.class);
}
}
Now you can inject a map of instances (or a map of providers of instances if you need to keep creating new instances) into your main class and use the string discovered at runtime to control which kind of instance you get.
public class BusinessLogic {
#Inject
private ServiceClientAdapter serviceClientAdapter;
#Inject
private Map<String, ServiceClientAdapter> mapBinder;
public void setupAndUseClientAdapter() {
String userType = getUserTypeFromLdapServer();
serviceClientAdapter = mapBinder.get(userType);
if (serviceClientAdapter == null) {
throw new IllegalArgumentException(
"No service client adapter available for " +
userType + " user type.";
}
doStuffWithServiceClientAdapter();
}
}
While working on an web-application , I need to get a set of classes at few steps and I am thinking to separate this logic to a simple Factory so as based on the Class type We can create class instance as well init it with default values.
Current structure of Class hierarchy is
public interface DataPopulator<Source,Target>{
// some method decaration
}
Abstract class
public abstract class AbstractDataPopulator<Source,Target> implements DataPopulator<Source, Target>{
// some common implimentation
}
And now classes which will be used as actual implementations like
Type1Populator extends AbstractDataPopulator.
Type2Populator extends AbstractDataPopulator.
Each of these implementation needs a set of common dependencies based on what functionality is being executed by those Populators.
As of Now I am creating instance with new and than filling those dependencies with simple setter methods.
I am thinking about creating a simple factory pattern like
public interface PopulatorFactory{
<T extends Object> T create(String className) throws Exception;
<T extends Object> T create(Class populatorClass) throws Exception;
}
Abstract class
public abstract class DefaultPopulatorFactory impliments PopulatorFactory{
public <T> T create(final Class populatorClass) throws Exception{
return Class.forName(populatorClass);
}
// other method.
}
Implementation classes
public Type1PopulatorFactory extends DefaultPopulatorFactory {
public <T> T create(final Class populatorClass) throws Exception{
final T populator= super.create(populatorClass);
}
}
I also want to initialize newly created instances with some default values specific to each implementation, but I'm not sure what's the best way to do this?
Should I define another method say initDefaults?
What is the best way to pass those dependencies to these poulators.
Is the approach outlined by me fine or is it overly complicated?
In cases when you are building not-so-trivial objects it is usually better to use the Builder pattern instead of a Factory.
In your case if you don't need external data sources you can simply write constructors for your classes where you can supply the default values and get rid of the contraption in your question.
If you use the Builder pattern you can simplify your framework by using a Builder object for the common data and a SomeOtherBuilder which extends from Builder and adds the custom values of the specialized implementation. You can make your classes constructors which are taking a Builder object.
public class Builder {
// your fields go here
}
public class SomeOtherBuilder extends Builder {
// your specialized fields go here
}
public class YourClass {
public YourClass(Builder builder) {
// construct it here
}
}
You can also make your classes generic with using something like T extends Builder.