Why can't Guice bind for an intermediate dependency? - java

Here's my code:
// Groovy
interface MyMapper {
Buzz toBuzz(Fizz fizz);
}
class MyMapperImpl implements MyMapper {
#Named("SIMPLE_FOOBAR")
Foobar foobar;
MyMapperImpl(Foobar foobar) {
super();
this.foobar = foobar;
}
#Override
Buzz toBuzz(Fizz fizz) {
// ...etc.
}
}
class Whistlefeather {
MyMapper mapper;
Whistlefeather(MyMapper mapper) {
super();
this.mapper = mapper;
}
void doSomething(Fink fink) {
Fizz fizz = getSomehow(fink);
Buzz buzz = mapper.toBuzz(fizz);
// Do something with 'buzz'...
}
}
class ApplicationMain {
Whistlefeather whistlefeather;
#Inject
ApplicationMain(Whistlefeather whistlefeather) {
super();
this.whistlefeather = whistlefeather;
}
static void main(String[] args) {
Injector injector = Guice.createInjector(new ApplicationModule());
ApplicationMain appMain = injector.getInstance(ApplicationMain);
appMain.run();
}
void run() {
whistlefeather.doSomething(new Fink());
}
}
Here's my Guice module:
class ApplicationModule extends AbstractModule {
#Override
protected void configure() {
// I have to name the Foobars because in reality there will be
// *many* of them, each configured slightly different.
bind(Foobar.class).annotatedWith(Names.named("SIMPLE_FOOBAR"))
.toInstance(new Foobar(true, true, false, 103, "yee haw"));
bind(MyMapper.class).to(MyMapperImpl);
}
}
Here's my exception:
Could not find a suitable constructor in com.me.myapp.MyMapperImpl.
Classes must have either one (and only one) constructor annotated
with #Inject or a zero-argument constructor that is not private.
My understanding was that I only need to annotate constructors with #Inject if I would be directly calling them through the Injector#getInstance(...) method. Since I do this with ApplicationMain, which contains a reference to Whistlefeather, which contains a reference to MyMapper, I didn't think I would have to annotate the MyMapperImpl constructor.
Any ideas as to where I'm going awry here?

In order for Guice to create any object, it has to know which constructor to use. This is true all the way down the Object Graph.
Consider the following code:
public interface Something { }
public class SomethingImpl implements Something {
private final String data;
public SomethingImpl(String data) {
this.data = data;
}
public SomethingImpl(Integer data) {
this.data = data.toString();
}
}
public class AnotherClass {
private final Something something;
#Inject
public AnotherClass(Something something) {
this.something = something;
}
}
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(Something.class).to(SomethingImpl.class);
bind(String.class).toInstance("Hello!");
bind(Integer.class).toInstance(50);
}
}
In this scenario, how is Guice supposed to know which constructor to use in SomethingImpl? If you were the author of Guice, how would you write it?
Obviously, you can't answer, because it's impossible. There has to be some sort of mechanism to tell Guice which constructor to use, regardless of whether or not it's called by Injector.getInstance() or not; that's why you have to annotate at least one constructor. Guice will use a no-argument constructor by default if one is specified, but if there isn't one, Guice doesn't know what to do.

Related

How to avoid duplicated if statements

I have multiple services that implement interface with one method - execute(). Each service uses this method to execute some actions based on a String value, which, in original code, is enum, so those values are constants.
interface Service{
public void execute();
}
class Service1 implements Service{
//constructors
public void execute(JSONObject payload, String payloadType){
if(payloadType.equals("type1")){
doSomething(payload);
}
}
}
class Service2 implements Service{
//constructors
public void execute(JSONObject payload, String payloadType){
if(payloadType.equals("type1")){
doSomething1(payload);
}
if(payloadType.equals("type2")){
doSomething2(payload);
}
}
}
I want to avoid writing same if statements each time I create a new Service. Problem is, that each Service doesn't have to execute actions based on each string types. So Service1 executes action when type is equal to "type1", however Service2 executes actions based on "type1" and "type2".
I tried following solution:
class Main {
public static void main(String[] args) {
exec(new B(), "type2");
}
private static void exec(Service service, JSONObject payload, String payloadType){
if(payloadType.equals("type1")){
Init i = (Init)service;
i.init(payload);
}
if(payloadType.equals("type2")){
Action a = (Action)service;
a.action(payload);
}
}
}
interface Service{
}
interface Init{
public void init(JSONObject payload);
}
interface Action{
public void action(JSONObject payload);
}
class A implements Service, Init{
#Override
public void init(JSONObject payload){
doSomething(payload);
}
}
class B implements Service, Init, Action{
#Override
public void init(JSONObject payload){
doSomething1(payload);
}
#Override
public void action(JSONObject payload){
doSomething2(payload);
}
}
The above code works, but I don't like using casting. I think it's not a good practice, also very unsafe. Could you suggest, what design pattern or other solution could I use here? I tried visitor, but I couldn't figure out the right implementation with this case.
UPDATE
Thanks for all the answers, they were very helpfull. I managed to achieve what I was looking for. Here's the code that finally works.
public class Main {
public static B b = new B();
public static A a = new A();
public static void main(String[] args) {
exec(b, "init");
}
private static void exec(Service service, String type){
if(type.equals("init") && service instanceof Init){
service.fillCarrier(new InitCarrier());
}
if(type.equals("action") && service instanceof Action){
service.fillCarrier(new ActionCarrier());
}
}
}
interface Carrier<T>{
public void set(T t);
}
class InitCarrier implements Carrier<Init>{
public void set(Init init){
init.init();
}
}
class ActionCarrier implements Carrier<Action>{
public void set(Action action){
action.action();
}
}
abstract class Service{
public void fillCarrier(Carrier carrier){
carrier.set(this);
}
}
interface Init{
public void init();
}
interface Action {
public void action();
}
class A extends Service implements Init{
#Override
public void init(){
System.out.println("init a");
}
}
class B extends Service implements Init, Action{
#Override
public void init() {
System.out.println("init b");
}
#Override
public void action(){
System.out.println("action");
}
}
To achieve this requirement, we need to pattern.
Factory pattern.
Strategy pattern.
TypeFactory creates an object based on the string we delivered. Each Type implementation implements a doSomething() method in its own way. (factory pattern is used here)
Type Strategy:
interface Type{
public void doSomething();
}
class TypeOne implements Type{
#Override
public void doSomething() {
System.out.println("Type One!");
}
}
class TypeTwo implements Type{
#Override
public void doSomething() {
System.out.println("Type Two!");
}
}
Type Factory:
class TypeFactory{
Type type;
public Type createType(String condition) {
if (condition == null || condition.isEmpty()) {
return null;
}
if ("type1".equals(condition)) {
return new TypeOne();
}
else if ("type2".equals(condition)) {
return new TypeTwo();
}
return null;
}
}
Now to achieve the final goal, we need to declare a Service interface with an execute method. This execute method takes Type as an input parameter. Based on which type you actually pass, the corresponding doSometing method will be invoked. (strategy pattern used only)
interface Service{
public void execute(Type type);
}
class ServiceOne implements Service{
#Override
public void execute(Type type) {
System.out.print("Service One - ");
type.doSomething();
}
}
class ServiceTwo implements Service{
#Override
public void execute(Type type) {
System.out.print("Service Two - ");
type.doSomething();
}
}
Main Class looks like this:
public class DesignPatternCombo {
public static void main(String[] args) {
Type typeOne = new TypeFactory().createType("type1");
Type typeTwo = new TypeFactory().createType("type2");
Service serviceOne = new ServiceOne();
serviceOne.execute(typeOne);
Service serviceTwo = new ServiceTwo();
serviceTwo.execute(typeOne);
serviceTwo.execute(typeTwo);
}
}
Expected output:
Service One - Type One!
Service Two - Type One!
Service Two - Type Two!
Tricky question, I may have a solution that could work.
That would be to store the Types, with the code that type does in the form of a HashMap.
HashMap<String, Function<Void, Void>> types = new HashMap<String, Function<Void, Void>>();
Then in the main function, you would fill up the HashMap with the names of the types, and the function it runs.
types.put("Type1",()->{
/*Do something*/
});
types.put("Type2",()->{
/*Do something*/
});
types.put("Type3",()->{
/*Do something*/
});
Then in the Service, you would have an array of Strings for what types it uses. Such as:
String[] serviceTypes = {"Type1", "Type2"};
Finally, in the execute function of the Service you would run the corresponding lambda to the string.
public void execute(String type){
if((new ArrayList<>(Arrays.asList(serviceTypes))).contains(type)) {
Main.types.get(type);
}
}
You might work with an abstract base class.
The base class implements Service and has the execute() method. It does not get around if statements, but after all it could have a list of allowed values, and as soon as the type parameter is contained in the list it would call another method. Per default the method does nothing.
Concise subclasses of the base no longer need to perform the if conditions as they simply override the single methods in the base class. So this works for a whole bunch of quite similar services.
The advantage of this approach is if you have some exotic, incompatible type of service you can skip the if statements by directly overwriting the execute() method. So that pattern is extensible, which is probably worth more than saving a few more if statements.
You can solve this elegantly with the Strategy Design Pattern.
Create a common interface called Strategy
interface Strategy {
void execute(JSONObject payload);
}
Create multiple implementations of Strategy according to your needs:
class ServiceType1 implements Strategy {
//constructors and fields
#Override
public void execute(JSONObject payload) {
//code to be executed for "type1"
}
}
class ServiceType2 implements Strategy {
//constructors and fields
#Override
public void execute(JSONObject payload) {
//code to be executed for "type2"
}
}
...
Group the Service implementations by type, eg.:
Map<String, Strategy> strategyMap = new HashMap<>();
strategyMap.put("type1", new ServiceType1());
strategyMap.put("type2", new ServiceType2());
...
Invoke the desired Service without the need for any if statements, like this:
private static void exec(String payloadType, JSONObject payload) {
strategyMap.get(payloadType).execute(payload);
}
P.S.: if all implementations of Strategy share some common behaviour, you can convert Strategy from interface to abstract class and move the common behaviour there.
wow, your architecture seems much complex. you should consider better hierarchy. but if you can't, why don't you just make a method on Service and let the subtype decide what behavior they want. Then you can call that method from Service to execute
static class Main {
public static void main(String[] args) {
exec(new B());
}
private static void exec(Service service){
service.execute();
}
}
interface Service{
void execute();
}
interface Init{
public void init();
}
interface Action{
public void action();
}
static class A implements Service, Init{
#Override
public void init(){
System.out.println("init a");
}
#Override
public void execute(){
init();
}
}
static class B implements Service, Init, Action{
#Override
public void init(){
System.out.println("init b");
}
#Override
public void action(){
System.out.println("action");
}
#Override
public void execute(){
action();
}
}
What about extracting common logic to the separate class. It cloud be:
BaseService and all other services should implement this one;
ServiceDelegate and all other services should delegate all work to this one.
The below snippet provides the first solution.
// This is you Service interface
public interface Service {
void execute(JSONObject payload, String payloadType);
}
// This is base implementation. Use `Map` to replace `if` statements
public abstract class BaseService implements Service {
private static final Consumer<JSONObject> NULL = jsonObject -> { };
private final Map<String, Consumer<JSONObject>> consumers;
protected BaseService(Map<String, Consumer<JSONObject>> consumers) {
this.consumers = consumers == null || consumers.isEmpty() ? Map.of()
: Collections.unmodifiableMap(consumers);
}
#Override
public final void execute(JSONObject payload, String payloadType) {
consumers.getOrDefault(payloadType, NULL).accept(payload);
}
}
public class ConcreteService extends BaseService {
private static final Consumer<JSONObject> DO_SOMETHING_TYPE1 = jsonObject -> {
// TODO implementation for "type1"
};
private static final Consumer<JSONObject> DO_SOMETHING_TYPE2 = jsonObject -> {
// TODO implementation for "type2"
};
public ConcreteService() {
super(Map.of(
"type1", DO_SOMETHING_TYPE1,
"type2", DO_SOMETHING_TYPE2));
}
}

How to use Guice Assisted Inject for this factory pattern?

The following is a factory pattern that I wrote. But, in order to change it into a Provider, Guice documentation is not quite helping.
class ClientA extends AbstractClient {...}
class ClientB extends AbstractClient {...}
class ClientUtil {
private static AbstractClient client;
public static AbstractClient getClient(String key) {
ClientType clientType = ....
switch(clientType) {
case ".." : client = new ClientA.Builder()....build();
break;
case "..." :
default : client= new ClientB.Builder()....build();
}
return client;
}
}
class Application {
AbstractClient client = ClientUtil.getClient(key); // here, key is a string which is dynamic
}
Please provide some suggestions on how this can be written in a Provider format with Guice AssistedInject.
Did you try to write your Factory manually? The manual you linked has a nice example, and your code will translate easily to Guice.
public interface ClientFactory {
AbstractClient create(String key);
}
public class ClientFactoryImpl implements ClientFactory {
#Override
public AbstractClient create(String key) {
if ("A".equals(key)) {
return new ClientA();
} else {
return new ClientB();
}
}
}
and bind factory to implenetation
bind(ClientFactory.class).to(ClientFactoryImpl.class);
AssistedInject is detrimental in your case. All it offers is building ClientFactoryImpl automatically. The implementation only passes injected and assisted arguments to the constructor. But you have some non-trivial logic in the create method. In this case, I suggest you create factory implementation yourself.
First off, I would definitely agree with #Lesiak. The code client= new ClientB.Builder()....build(); isn't clear as the ellipsis could be any number of fields you're setting on ClientA/B.
But to give you an example of how to use AssistedInject for your particular instance:
class ClientA extends AbstractClient {
#Inject
public ClientA(ServiceOne serviceOne,
ServiceTwo serviceTwo,
#Assisted MyObject myObject) {
...
}
}
class ClientB extends AbstractClient {
// Same constructor as ClientA
}
Your factory would then look something like:
interface ClientFactory {
#Named("ClientA") public AbstractClient getClientA(...);
#Named("ClientB") public AbstractClient getClientB(...);
}
Your parameters can be different objects, or whatever you want, but they essentially have to matchup with the constructor #Assisted annotation. You can see now why #Lesiak provided the answer he did, if your builder is setting 10 fields on ClientA, then your factory method will need to have 10 method parameters, and is very unruly.
You'd then use this with:
#Inject ClientFactory clientFactory;
...
AbstractClient client = clientFactory.getClientA(something, something1, ...);
...
Assuming you want to create the Object directly and thus need to use #Assisted you can let Guice create named factories:
import javax.inject.Inject;
// com.google.inject:guice:4.2.2
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
// com.google.inject.extensions:guice-assistedinject:4.2.2
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.FactoryModuleBuilder;
public class StackOverflow {
public static void main(String[] args) {
final Injector injector = Guice.createInjector(new GuiceModule());
Key<ClientFactory> key = Key.get(ClientFactory.class, Names.named(args[0]));
System.out.println("Client: " + injector.getInstance(key).create("xxx"));
}
}
class GuiceModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder().implement(AbstractClient.class, ClientA.class)
.build(Key.get(ClientFactory.class, Names.named("ClientA"))));
install(new FactoryModuleBuilder().implement(AbstractClient.class, ClientB.class)
.build(Key.get(ClientFactory.class, Names.named("ClientB"))));
}
}
abstract class AbstractClient {
}
class ClientA extends AbstractClient {
private String key;
#Inject
public ClientA(#Assisted String key) {
this.key = key;
}
#Override
public String toString() {
return "ClientA [key=" + key + "]";
}
}
class ClientB extends AbstractClient {
private String key;
private Injector injector; // just an example for additional injections
#Inject
public ClientB(#Assisted String key, Injector injector) {
this.key = key;
this.injector = injector;
}
#Override
public String toString() {
return "ClientB [key=" + key + "]";
}
}
interface ClientFactory {
AbstractClient create(String key);
}
The downside to this approach is that in order to use a dynamic input you need a reference to the Injector and Guice complains that this is very slow - that may not be an issue for you tough. If somebody knows how to replace the direct injector.getInstance call with something better please let me know!

Guice inject an object to a class constructor

I just started looking at Guice for a new project. I have something like this
the ConfigImpl class ans Config interface
interface Config{...}
class ConfigImpl implements Config {
private static final Map<> propMap;
public ConfigImpl(Map<> propMap) {
this.propMap = someProps;
}
}
Guice injection I came up with
public class MyInjector extends AbstractModule {
protected void configure() {
bind(Config.class).to(ConfigImpl.class)
}
}
and finally
public SomeClass {
Config someConfig;
Injector injector = Guice.createInjector(new MyInjector());
someConfig = injector.getInstance(Config.class);
}
Now I am very confused as I can't find a way to pass propMap into ConfigImpl class. I'd like to know the proper way of doing it in Guice. Thanks!
You should inject propMaps from your module:
public class MyInjector extends AbstractModule {
private final Map<String,String> mapProps;
public MyInjector(Map<String,String> mapProps) {
this.mapProps = mapProps;
}
protected void configure() {
bind(Config.class).to(ConfigImpl.class).in(Scope.SINGLETON); // You most than likely want this
bind(new TypeLiteral<Map<String,String>>() {}).toInstance(mapProps); // binding for the map.
}
}
And use it like this:
public class SomeClass {
void doSomething() {
Map<String,String> mapProps = ... ;
Injector injector = Guice.createInjector(new MyInjector(mapProps));
Config someConfig = injector.getInstance(Config.class);
}
}
Also, you should fix your ConfigImpl class:
class ConfigImpl implements Config {
private final Map<String,String> propMap;
#Inject // mandatory since you use a non-default constructor
public ConfigImpl(Map<String,String> propMap) { // add the generic type of the map
this.propMap = propMap;
}
}

Defining bean with two possible implementations

So far, I had a very simple bean definition that looked like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return new ImplementationOne();
}
However, I now have situation where additional implementation class has been added, let's call it ImplementationTwo, which needs to be used instead of ImplementationOne when the option is enabled in configuration file.
So what I need is something like this:
#Bean
#Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
return context.getEnvironment().getProperty("optionEnabled") ? new
ImplementationOne() : new ImplementationTwo();
}
Basically a way to instantiate correct implementation at bean definition time based on the configuration value. Is this possible and can anyone please provide an example? Thanks
It is possible to implement this without using #Conditional.
Assuming you have a Interface SomeInterface and two implementations ImplOne ImplTwo:
SomeInterface.java
public interface SomeInterface {
void someMethod();
}
ImplOne.java
public class ImplOne implements SomeInterface{
#Override
public void someMethod() {
// do something
}
}
ImplTwo.java
public class ImplTwo implements SomeInterface{
#Override
public void someMethod() {
// do something else
}
}
Then you can control which implementation is used in a configuration class like this:
MyConfig.java
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext context;
#Bean
public SomeInterface someInterface() {
if (this.context.getEnvironment().getProperty("implementation") != null) {
return new ImplementationOne();
} else {
return new ImplementationTwo();
}
}
}
Make sure that the component scan of spring finds MyConfig. Then you can use #Autowired to inject the right implementation anywhere else in your code.
I think you are doing it wrong.
You should use #Conditional() on your implementation and not on your Interface.
Here is how I would do it :
The interface you will use on your code.
MyInterface.java
public interface MyInterface {
void myMethod();
}
The first implementation :
MyInterfaceImplOne.java
#Bean
#Conditional(MyInterfaceImplOneCondition.class)
public class MyInterfaceImplOne implements MyInterface {
void myMethod(){
// dosmthg
}
}
MyInterfaceImplOneCondition.java
public class MyInterfaceImplOneCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("optionEnabled")
}
}
And for the 2nd implementation :
MyInterfaceImplTwo.java
#Bean
#Conditional(MyInterfaceImplTwoCondition.class)
public class MyInterfaceImplTwo implements MyInterface {
void myMethod(){
// dosmthg 2
}
}
MyInterfaceImplTwoCondition.java
public class MyInterfaceImplTwoCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getEnvironment().getProperty("optionEnabled")
}
}
In that case, you now just have to call the interface, and Spring will inject the bean corresponding to the right condition.
Hope it is what you are looking for, and I was clear enough!

Inject a TypeListener

I have this scenario where I want to inject a TypeListener with dependencies, but it will never work because the TypeListener is used to actually perform the injection.
How can I get this thing done? Is there a guicey-way?
Notes:
I'm using Guice 4.0
MyManager will be used after Guice::createInjector.
Both MyManager::registerType and MyManager::use are called exclusively before Guice::createInjector returns.
MyDependency is present to show that MyManager cannot be instanciated with new. I will also be used after Guice::createInjector has returned.
I created the following SSCCE to showcase my issue:
import com.google.inject.*;
import com.google.inject.matcher.*;
import com.google.inject.spi.*;
public class MyClass {
public static void main(String[] args) {
Guice.createInjector(new MyModule());
}
static class MyModule extends AbstractModule {
#Override protected void configure() {
TypeListener listener = new MyTypeListener();
requestInjection(listener);
bindListener(Matchers.any(), listener);
}
}
static class MyTypeListener implements TypeListener {
#Inject MyManager manager;
#Override public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
Class<?> rawType = type.getRawType();
manager.registerType(rawType);
encounter.register(new InjectionListener<I>() {
#Override public void afterInjection(I injectee) {
manager.use(rawType, injectee);
}
});
}
}
#Singleton static class MyManager {
#Inject MyManager(MyDependency dependency) { }
void registerType(Class<?> type) { }
void use(Class<?> type, Object injectee) { }
}
static class MyDependency { }
}
I think at least some of the time (in tests or code analysis) type listeners have no cohesion to the types they are listening to, so there's no reason to have one injector. You'd use one injector to create the listener and one injector to create the code to be tested/analyzed.
If you really want one injector (e.g. if the types in the injector you wish to listen to and the types needed by the listener are cohesive) then your best bet is AbstractModule's getProvider() method. So, if MyTypeListener needs an instance of Foo, this is what MyModule would look like:
static class MyModule extends AbstractModule {
#Override protected void configure() {
TypeListener listener = new MyTypeListener(getProvider(Foo.class));
bindListener(Matchers.any(), listener);
}
}
If you haven't used getProvider(), be forewarned that you cannot call .get() on the provider until the injector is constructed. As long as you don't call it from the context of the listener's constructor you should be fine.

Categories