6

I have a play framework application which I have migrated to run on play framework 2.4.2. It is providing a RESTful API to a javascript/html frontend. Now I have some problems introducing caching.

LibraryController (transforming JSON/HTTP request to JSON/HTTP response):

public class LibraryController extends Controller {

  public Result getBook(String isbn) {
      Book book = LibraryManager.getBook(isbn);
      BookDto bookDto = DtoMapper.book2BookDtos(book);
      return ok(Json.toJson(bookDto));
  }
}

LibraryManager (transforming domain model request to domain model response):

public class LibraryManager {

@Inject CacheApi cache;

public static Book getBook(String isbn) {

    Book book = cache.get(isbn);
    // ...
}

The problem I have here is that I get

non-static variable cache cannot be referenced from a static context

The way I am injecting the cache is as per Play 2.4.2 Cache API documentation. I didn't have this problem when I used caching as per the Play 2.2.x Cache API documentation. That version had a static method I could call.

What should I do? Should I make getBook non-static applying some singleton pattern? Or should I access the cache in some other way? Sample code would surely help out!

nize
  • 1,012
  • 1
  • 11
  • 27
  • 1
    Why is your getBook method static anyway? – thwiegan Aug 05 '15 at 13:31
  • The reason why getBook is static is because it seemed overkilling instantiating a new object just to serve requests and access data sources (external web APIs etc). The domain model classes are instantiated. Is the reasoning invalid? – nize Aug 05 '15 at 13:36
  • 1
    Usually you don't want anything static when you use Play. Just instantiate the LibraryManager within the Controller and make getBook non-static. – thwiegan Aug 05 '15 at 13:50
  • For anyone stumbling upon this question in the present, CacheApi is now deprecated - ```@deprecated Deprecated as of 2.6.0. Use {@link SyncCacheApi} or {@link AsyncCacheApi}``` – Siddhartha Dec 11 '17 at 23:56

2 Answers2

8

Make Guice aware of LibraryManager using @Singleton annotation, remove static keyword from methods and pull them up to interface:

@ImplementedBy(LibraryManager.class)
public interface ILibraryManager {
    //
}

@Singleton
public class LibraryManager implements ILibraryManager {

    @Inject
    private CacheApi cache;

    @Override
    public Book getBook(String isbn) {
        Book book = cache.get(isbn);
        // ...
    }

}

Now you can inject LibraryManager by an interface to your controller:

public class LibraryController extends Controller {

    @Inject
    private ILibraryManager libraryManager;

}

Congratulations! You decoupled LibraryManager and integrated it with Play 2.4 in proper way.

Mon Calamari
  • 4,403
  • 3
  • 26
  • 44
  • 2
    I followed the guide in this answer. In addition to the lines above I found that I had to add `routesGenerator := InjectedRoutesGenerator` to build.sbt since my controller method actually also had the `static` keyword. Moreover, I added `import com.google.inject.ImplementedBy; @ImplementedBy(LibraryManager.class) public interface ILibraryManager {` in order to configure which implementation to use. – nize Aug 05 '15 at 18:19
1

Get instance of CacheApi.class inside static finction.

    public class LibraryManager {

    public static Book getBook(String isbn) {
      CacheApi cache = Play.current().injector().instanceOf(CacheApi.class);
      Book book = cache.get(isbn);
    // ...
    }
  • I would note that this is deprecated in 2.5.x and removed in 2.6.x. It also introduces coupling which is against the entire point of using an injector. See this [answer](https://stackoverflow.com/a/38143271/2510651) as well. – Matias Grioni Mar 31 '19 at 02:23