3

Hi I can't inject the RestService anywhere in my code. I'm working test driven so I am using Robolectric to test this code. I hope it isn't a problem with AA+Robolectric, I don't have any experience with this. The weird thing is that in my tests I can manually insert the generated RestClient_, but it doesn't get inserted automatically. So I can do this:

RestClient rest = new RestClient_(activity.getApplicationContext());

but the following doesn't work:

@RestService
RestClient restClient;

I get a NullPointerException on restClient.

I also didn't forget the @EBean tag

@EBean
public class Player {
    @RestService
    RestClient restClient;

    private int playerId;

    public Player() {
    }

    public int getPlayerId() {
        return playerId;
    }

    public List<Card> getHand() {
        return restClient.getHand(playerId);
    }
}

In the log I can see that Android Annotations has processed everything correctly.

This is my first project with Android Annotations and I can't grasp why the dependency injection doesn't work. No dependency injection removes almost all the benefit of using Android Annotations. Thanks in advance!

Some extra information: I am instantiating my Player object in an Android Annotations-annotated REST Service. A code snippet of the method creating the Player object.

@Get(value = "/players/createAnonymous")
@Accept(MediaType.APPLICATION_JSON)
public Player createAnonymousPlayer();
GoGoris
  • 820
  • 8
  • 20
  • How do you create an instance of `Player`? – WonderCsabo Feb 09 '15 at 22:19
  • This is an object that I get from the rest service in another class using the gsonserializer. – GoGoris Feb 10 '15 at 09:43
  • That will not work. You should use the `Player_` subclass, which will have dependency injection. However, i think these objects should be just simple POJOs, which are coming from the REST end point. – WonderCsabo Feb 10 '15 at 10:18
  • Yes I see, thank you. So Android Annotations doesn't seem very testable. It's true I can't return an EBean in the REST service. This is a big drawback I think. – GoGoris Feb 10 '15 at 13:51
  • You can, if you create a customized `Converter`, but i do not think you should actually. – WonderCsabo Feb 10 '15 at 15:00

1 Answers1

0

Ok so here is the answer to my question. I hope it can be of use to other people who ask themselves the same as I did. Thanks to WonderCsabo for pointing me in the right direction.

Android Annotations generates the annotated classes at compile time. So Player becomes Player_. When using @Inject, Android Annotations will inject an instance of Player_ in the annotated field. However in my case the RestClient_ will return Player and not Player_ (So the player object without the processed annotations, so without the injected RestClient_).

It's not possible (not that I know of) to make the RestClient return Player_. This will not compile because the Player_ class doesn't exist yet at compile time.

Now I also understand the drawback that Android Annotations has. You can't easily test the code because you can't use android annotations in your tests. You can't swap the testclass with the generated class anywhere. You can't mock the injected classes either without using a runtime mock generator as PowerMock. So if you need dependency injection and easy testing, you should look elsewhere. (Dagger for example)

GoGoris
  • 820
  • 8
  • 20
  • Sorry, but you are totally wrong. AndroidAnnotations works completely at compile time, since it is an annotation processor. The `Player_` class exists at compile time, and you can use it. With a customized `Converter` you can return `Player_` instances. It is true that AA dependency injection is far too simple, and you cannot add a test `Module` for example. About testing code with AA, read [this](https://github.com/excilys/androidannotations/wiki/Unit-test-your-application). – WonderCsabo Feb 10 '15 at 15:04
  • I'm sorry it is indeed right after compile time. I was confused because of this: if I say my restservice returns Player_, it can't find Player_ because javac removed the import of Player_. I think this is because it can't see that the class is used? – GoGoris Feb 10 '15 at 19:51
  • Thanks for the link, I didn't knew that I could inject mocks in it that way, but it's still a devious way to do it. – GoGoris Feb 10 '15 at 20:01
  • The class is totally existing at compile time. Actually the annotation processing runs before the compilation. – WonderCsabo Feb 11 '15 at 11:27
  • That's weird, when I check the compiled RestClient_ (while debugging) the Player_ import is gone and Player_ is red underlined. I get a message that Player_ is not found. So for the java compiler removed the import of Player while compiling the class. I don't know why exactly but this is what happened. – GoGoris Feb 17 '15 at 15:41
  • What IDE are you using? I doubt the compiler removed the import... It is the IDEs fault by not displaying the source correctly. I guess the inspection says that the Player_ class cannot be resolved. – WonderCsabo Feb 17 '15 at 17:14
  • Android studio, It was just gone while debugging. – GoGoris May 21 '15 at 19:39
  • I cannot imagine that. You should upload a small test project which can reproduce the issue, other way we cannot investigate the problem. – WonderCsabo May 21 '15 at 21:20