Re: Specify concrete implementation for class

52 views
Skip to first unread message

Moandji Ezana

unread,
Dec 16, 2012, 6:27:48 AM12/16/12
to google...@googlegroups.com

Simply inject FileReader into CachedFileReader instead of IFileReader.

Moandji

On Dec 16, 2012 1:11 PM, "Dirk Nimerem" <nene...@sinnlos-mail.de> wrote:
Hello,

i defined the following interface:

@ImplementedBy(FileSystem.class)
public interface IFileSystem {
public String getFileContent(String filepath) throws IOException;
public long getLastModified(String filepath) throws IOException;
}

and implementing class:

@Singleton
public class FileReader implements IFileReader {   
@Override
public String getFileContent(String filepath) throws IOException {
return FileUtils.readFileToString(new File(filepath));
}

@Override
public String
getLastModified(String filepath) throws IOException {
return (new File(filepath)).lastModified();
}
}

This should encapsulate these file operations on the harddisk. And I'm also able to mock this interface while testing my classes.
Now i would like to provide a CachedFileReader implementing which should cache any file (I keep the example as small as possible without take note on file changes or anything else):

@Singleton
public class CachedFileReader implements IFileReader {
private final HashMap<String, String> cache = new HashMap<String, String> ();
private final
IFileReader filereader;
   
@Override
public String getFileContent(String filepath) throws IOException {
String key = filepath + String.valueOf(getLastModified(filepath)); // I know this is a crap solution, its just for this example

if (!(cache.containsKey(filepath)) {
cache.put(filepath, filereader.getFileContent(filepath));
}
return cache.get(filepath);
}

@Override
public String getLastModified(String filepath) throws IOException {
return filereader.getLastModified(filepath);
}

@Inject
public
CachedFileReader(IFileReader filereader) {
this.filereader = filereader;
}
}

I haven't inherited from FileReader because I want later be able to test the CachedFileReader itself with a IFileReader mock object passed to the constructor.
Also I changed the @ImplementedBy Annotation of my IFileReader interface to CachedFileReader. So every class which needs a IFileReader now gets the CachedFileReader instance.

But how can I tell Google Juice tell that it should inject the normal FileReader to the constructor of the CachedFileReader instead of itself? Is there an annotation for that? I have read about multibindings but it didn't helped me. Or is there a better solution for my concern?

Thank you in advance,
Dirk

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/Q0mkVSYi3RsJ.
To post to this group, send email to google...@googlegroups.com.
To unsubscribe from this group, send email to google-guice...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-guice?hl=en.

Dirk Nimerem

unread,
Dec 16, 2012, 8:05:32 AM12/16/12
to google...@googlegroups.com
Hello Moandji,

I want to test the CachedFileReader later with a simple test and a mock a IFileReader like this:

IFileReader mockreader = MockCreater.createMock(IFileReader filereader);
CachedFileReader objecttotest = new CachedFileReader(filereader);

Is it a good idea to inject the FileReader directly into the CachedFileReader? My CachedFileReader class then directly depends on a concrete class not on an interface. I imagine I could create another HttpFileReader class. Then my CachedFileReader should use the HttpFileReader within the constructor via guice not the "normal" FileReader class. Is there a solution for this problem?

But this solution is at least much better than my current workaround, thank you.

Dirk

Moandji Ezana

unread,
Dec 16, 2012, 8:17:31 AM12/16/12
to google...@googlegroups.com

You can mock concrete classes with Mockito.

If you really want to inject an interface even if you know which implementation you need, you can use binding annotations.

I don't really see the point of specifying an IFileReader if you know you need a caching or HTTP-aware version. Similarly, binding annotations are often a weaker and more difficult to understand version of what the standard type system gives you.

Moandji

To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/dNFiHY_eurwJ.

Dirk Nimerem

unread,
Dec 17, 2012, 9:52:51 AM12/17/12
to google...@googlegroups.com
Hello Moandji,

could you please make an example how to specifiy a binding via annotation for this?

Any other class should use the CachedFileReader for an IFileReader, only the CachedFileReader itself should use the basic FileReader.

Dirk

Thomas Broyer

unread,
Dec 17, 2012, 10:13:45 AM12/17/12
to google...@googlegroups.com


On Monday, December 17, 2012 3:52:51 PM UTC+1, Dirk Nimerem wrote:
Hello Moandji,

could you please make an example how to specifiy a binding via annotation for this?

Any other class should use the CachedFileReader for an IFileReader, only the CachedFileReader itself should use the basic FileReader.

You know that the CachedFileReader's dependency on IFileReader is special, so annotate it in the constructor.

Simple example here with the @Named annotation:

@Inject CachedFileReader(@Named("non_cached") IFileReader fileReader) { … }

then:

// CachedFileReader uses the basic FileReader:
bind(IFileReader.class).annotatedWith(Names.named("non_cached")).to(FileReader.class);
// Every other class should be given the CachedFileReader:
bind(IFileReader.class).to(CachedFileReader.class);

Cédric Beust ♔

unread,
Dec 17, 2012, 12:19:00 PM12/17/12
to google...@googlegroups.com
And just for completeness, if you're not comfortable with strings as keys for your binding annotations, you can also use real annotations, which adds type safety (no risks of making a typo) and makes it easier to immediately find occurrences of these bindings from your IDE.


-- 
Cédric




--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/JFnMdRCakToJ.

Moandji Ezana

unread,
Dec 17, 2012, 2:28:35 PM12/17/12
to google...@googlegroups.com

I'm on a tablet, so I won't type out any examples, but it's well explained in the docs: http://code.google.com/p/google-guice/wiki/BindingAnnotations

If all classes use the cached implementation except for one, then bind the interface to the cached version and request the basic FileReader where necessary. No annotations needed.

Moandji

To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/zTMwtBhDlqkJ.

Dirk Nimerem

unread,
Dec 19, 2012, 9:26:28 AM12/19/12
to google...@googlegroups.com
Thank you guys, the @Named annotation for @Inject was exactly what i was looking for.

Merry Christmas and a Happy New Year,
Dirk
Reply all
Reply to author
Forward
0 new messages