Problems with Injection of Generic Dependency

53 views
Skip to first unread message

thomas....@web.de

unread,
May 3, 2007, 7:10:42 AM5/3/07
to google-guice
If I try to inject a Service Implementation into a generic service
Property I get this exception:
Exception in thread "main" com.google.inject.ConfigurationException:
Error at de.tutorials.Client.setService(Client.java:35) Binding to
de.tutorials.services.IService<de.tutorials.services.IRequest,
de.tutorials.services.IResponse> not found. No bindings to that type
were found.
at com.google.inject.BinderImpl
$RuntimeErrorHandler.handle(BinderImpl.java:426)
at
com.google.inject.AbstractErrorHandler.handle(AbstractErrorHandler.java:
30)
at
com.google.inject.ErrorMessages.handleMissingBinding(ErrorMessages.java:
46)
at com.google.inject.InjectorImpl
$MissingDependencyException.handle(InjectorImpl.java:791)
at
com.google.inject.InjectorImpl.addInjectorsForMembers(InjectorImpl.java:
389)
at
com.google.inject.InjectorImpl.addSingleInjectorsForMethods(InjectorImpl.java:
356)
at com.google.inject.InjectorImpl.addInjectors(InjectorImpl.java:351)
at com.google.inject.InjectorImpl$4.create(InjectorImpl.java:332)
at com.google.inject.InjectorImpl$4.create(InjectorImpl.java:329)
at com.google.inject.util.ReferenceCache.create(ReferenceCache.java:
53)
at
com.google.inject.util.AbstractReferenceCache.internalCreate(AbstractReferenceCache.java:
59)
at
com.google.inject.util.AbstractReferenceCache.get(AbstractReferenceCache.java:
116)
at
com.google.inject.ConstructorInjector.<init>(ConstructorInjector.java:
39)
at com.google.inject.InjectorImpl$7.create(InjectorImpl.java:601)
at com.google.inject.InjectorImpl$7.create(InjectorImpl.java:594)
at com.google.inject.util.ReferenceCache.create(ReferenceCache.java:
53)
at
com.google.inject.util.AbstractReferenceCache.internalCreate(AbstractReferenceCache.java:
59)
at
com.google.inject.util.AbstractReferenceCache.get(AbstractReferenceCache.java:
116)
at com.google.inject.InjectorImpl.getConstructor(InjectorImpl.java:
765)
at
com.google.inject.InjectorImpl.getImplicitBinding(InjectorImpl.java:
973)
at
com.google.inject.InjectorImpl.getInternalFactory(InjectorImpl.java:
308)
at com.google.inject.InjectorImpl.getProvider(InjectorImpl.java:693)
at com.google.inject.InjectorImpl.getProvider(InjectorImpl.java:689)
at com.google.inject.InjectorImpl.getInstance(InjectorImpl.java:728)
at de.tutorials.Main.main(Main.java:24)

If I remove the generic Type Parameters of the IService Dependency
then everything works as expected.

Here is the example:
Our generic Service Interface:
[java]
package de.tutorials.services;

/**
* @author Thomas.Darimont
*/
public interface IService<TRequest extends IRequest, TResponse extends
IResponse> {
TResponse process(TRequest request);
}
[/java]

IRequest:
[java]
package de.tutorials.services;
/**
* @author Thomas.Darimont
*/
public interface IRequest {
String getData();
void setData(String data);
}
[/java]

IResponse:
[java]
package de.tutorials.services;
public interface IResponse {
String getResult();
void setResult(String result);
}
[/java]

Concrete MockService Implementation:
[java]
/**
*
*/
package de.tutorials.services.internal.mock;

import com.google.inject.Singleton;

import de.tutorials.services.IService;

/**
* @author Thomas.Darimont
*
*/
@Singleton
public class MockService implements IService<MockRequest,
MockResponse> {
public MockResponse process(MockRequest request) {
MockResponse response = new MockResponse();
response.setResult(request.getData().toUpperCase());
return response;
}
}
[/java]

The MockRequest:
[java]
package de.tutorials.services.internal.mock;
import de.tutorials.services.IRequest;

/**
* @author Thomas.Darimont
*/
public class MockRequest implements IRequest {
String data;

/**
* @return the data
*/
public String getData() {
return data;
}

/**
* @param data the data to set
*/
public void setData(String data) {
this.data = data;
}
}
[/java]

The MockResponse:
[java]
package de.tutorials.services.internal.mock;
import de.tutorials.services.IResponse;
/**
* @author Thomas.Darimont
*/
public class MockResponse implements IResponse {
String result;
/**
* @return the result
*/
public String getResult() {
return result;
}

/**
* @param result the result to set
*/
public void setResult(String result) {
this.result = result;
}
}
[/java]

The MainModule:
[java]
package de.tutorials;
import com.google.inject.Binder;
import com.google.inject.Module;
import de.tutorials.services.IService;
import de.tutorials.services.internal.mock.MockService;
/**
* @author Thomas.Darimont
*/
public class MainModule implements Module {
public void configure(Binder binder) {
binder.bind(IService.class).to(MockService.class);
}
}
[/java]

Our Client:
[java]
/**
*
*/
package de.tutorials;

import com.google.inject.Inject;

import de.tutorials.services.IRequest;
import de.tutorials.services.IResponse;
import de.tutorials.services.IService;
import de.tutorials.services.internal.mock.MockRequest;

/**
* @author Thomas.Darimont
*
*/
public class Client {
IService<IRequest, IResponse> service;

/**
* @return the service
*/
public IService<IRequest, IResponse> getService() {
return service;
}

/**
* @param service
* the service to set
*/
@Inject
public void setService(IService<IRequest, IResponse> service) {
System.out.println("setService");
this.service = service;
}

public void start() {
IRequest request = new MockRequest();
request.setData("bubu");
IResponse response = getService().process(request);
System.out.println(response.getResult());
}
}
[/java]

Here is the Main Class:
[java]
package de.tutorials;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Thomas.Darimont
*/
public class Main {
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
// Bootstrap Guice Runtime
Injector injector = Guice.createInjector(new MainModule());
System.out.println(injector);
// Start Client
injector.getInstance(Client.class).start();
}
}
[/java]

Did I miss something?

Best regards,
Thomas

Dhanji R. Prasanna

unread,
May 3, 2007, 8:04:52 AM5/3/07
to google...@googlegroups.com
try changing:

bind(IService.class).to(MockService.class);

to:

bind(new TypeLiteral<IService<IRequest, IResponse>> { }).to(MockService.class);

Dhanji


If I try to inject a Service Implementation into a generic service
Property I get this exception:
Exception in thread "main" com.google.inject.ConfigurationException:
Error at de.tutorials.Client.setService (Client.java:35) Binding to

de.tutorials.services.IService<de.tutorials.services.IRequest,
de.tutorials.services.IResponse> not found. No bindings to that type
were found.
        at com.google.inject.BinderImpl
$RuntimeErrorHandler.handle(BinderImpl.java:426)
        at
com.google.inject.AbstractErrorHandler.handle(AbstractErrorHandler.java:
30)
        at
com.google.inject.ErrorMessages.handleMissingBinding(ErrorMessages.java :
46)
        at com.google.inject.InjectorImpl
$MissingDependencyException.handle(InjectorImpl.java:791)
        at
com.google.inject.InjectorImpl.addInjectorsForMembers(InjectorImpl.java:
389)
        at
com.google.inject.InjectorImpl.addSingleInjectorsForMethods(InjectorImpl.java:
356)
        at com.google.inject.InjectorImpl.addInjectors(InjectorImpl.java:351)
        at com.google.inject.InjectorImpl$4.create (InjectorImpl.java:332)
        at com.google.inject.InjectorImpl.getInstance (InjectorImpl.java:728)

Kevin Bourrillion

unread,
May 3, 2007, 11:03:36 AM5/3/07
to google...@googlegroups.com
I apologize that this doesn't appear in the user's guide and we'll address that.  For now, please refer to the Binder interface javadoc.

(btw, the fact that guice makes you do this contortion is actually a very good thing! :-))

K

Bob Lee

unread,
May 3, 2007, 12:01:47 PM5/3/07
to google...@googlegroups.com
FWIW, once Java 7 comes out (and after I update Guice), you should be able to say "IService<IRequest, IResponse>.class".

Bob

thomas....@googlemail.com

unread,
May 3, 2007, 4:51:29 PM5/3/07
to google-guice
Hello,

thanks for the replys :)

I wonder whether we could make this work right know, because in this
case the generic information is available via reflection:


[java]
/**
*
*/
package de.tutorials;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
* @author Tom
*
*/
public class GenericReflectionExample {

/**
* @param args
*/

public static void main(String[] args) throws Exception{
Client client = new Client();
ParameterizedType parameterizedType = (ParameterizedType)
client.getClass().getDeclaredMethod("getService").getGenericReturnType();
Type[] types = parameterizedType.getActualTypeArguments();
System.out.println("ActualTypeArguments " + types[0] + ", " +
types[1]);
}
}
[/java]

Gives:
ActualTypeArguments interface de.tutorials.services.IRequest,
interface de.tutorials.services.IResponse

So if you know the actual type arguments, you should have enough
information to be able to wire the approriate generic dependencies, or
am I wrong?

For this Client (same as in the example above):


[java]
/**
*
*/
package de.tutorials;

import com.google.inject.Inject;

import de.tutorials.configuration.Configurable;


import de.tutorials.services.IRequest;
import de.tutorials.services.IResponse;
import de.tutorials.services.IService;
import de.tutorials.services.internal.mock.MockRequest;

/**
* @author Thomas.Darimont
*
*/

@Configurable


public class Client {
IService<IRequest, IResponse> service;

/**
* @return the service
*/
public IService<IRequest, IResponse> getService() {
return service;
}

/**
* @param service
* the service to set
*/
@Inject
public void setService(IService<IRequest, IResponse> service) {
System.out.println("setService");
this.service = service;
}

public void start() {
IRequest request = new MockRequest();
request.setData("bubu");
IResponse response = getService().process(request);
System.out.println(response.getResult());
}
}
[/java]

Best regards,
Thomas

Gregory Kick

unread,
May 3, 2007, 5:02:06 PM5/3/07
to google...@googlegroups.com
I think the issue with what you've proposed is that your suggestion
removes the type safety that you get with bind(new
TypeLiteral<IService<IRequest, IResponse>> { }).to(MockService.class).
Since you're using IService.class as the parameter to bind(), it
returns an AnnotatedBindingBuilder<IService> whereas the bind() that
use the type literal returns an
AnnotatedBindingBuilder<IService<IRequest, IResponse>>. This ensures
that the parameter for to() is of the correct type with the correct
parameters.


--
Gregory Kick
http://kickstyle.net/

thomas....@googlemail.com

unread,
May 3, 2007, 5:18:24 PM5/3/07
to google-guice
Hello,

hmmm, have you already tried this TypeLiteral based solution?
binder.bind(new TypeLiteral<IService<IRequest, IResponse>>() {
}).to(MockService.class);

If I try this I get this compiler error:

The method to(Class<? extends IService<IRequest,IResponse>>) in the
type LinkedBindingBuilder<IService<IRequest,IResponse>> is not
applicable for the arguments (Class<MockService>)
de.tutorials.training.guice/src/de/tutorials MainModule.java

Best regards,
Thomas

Bob Lee

unread,
May 3, 2007, 5:23:41 PM5/3/07
to google...@googlegroups.com
MockService implements IService<MockRequest, MockResponse> which isn't compatible with IService<IRequest,IResponse>--parameter types are invariant.

MockService needs to implement IService<IRequest,IResponse> instead.

Bob

thomas....@googlemail.com

unread,
May 3, 2007, 5:29:00 PM5/3/07
to google-guice
Hello,

args... shame one me I couldn't see the wood for the trees :) Thanx :D

Best regards
Thomas

Reply all
Reply to author
Forward
0 new messages