How to use the play.cache.CacheApi in a static method in Play! Framework 2.4.2
Asked Answered
A

2

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!

Atheistic answered 5/8, 2015 at 13:29 Comment(4)
Why is your getBook method static anyway?Indiraindirect
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?Atheistic
Usually you don't want anything static when you use Play. Just instantiate the LibraryManager within the Controller and make getBook non-static.Indiraindirect
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}Stigma
A
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.

Argumentative answered 5/8, 2015 at 14:13 Comment(1)
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.Atheistic
M
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);
    // ...
    }
Migdaliamigeon answered 23/3, 2017 at 15:17 Comment(1)
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 as well.Budwig

© 2022 - 2024 — McMap. All rights reserved.