2

I have an AspectJ class using annotation @Aspect in my Java program and I would like to make a class constructor with an injection using @Inject to an interface class but it gave me error of NoAspectBoundException such as follow:

de.hpi.cloudraid.exception.InternalClientError: org.aspectj.lang.NoAspectBoundException: Exception while initializing de.hpi.cloudraid.service.MeasurementAspect: java.lang.NoSuchMethodError: de.hpi.cloudraid.service.MeasurementAspect: method <init>()V not found

Here is the snippet of my class:

@Aspect
public class MeasurementAspect {

    private final RemoteStatisticService remoteStatisticService;

    @Inject
    public MeasurementAspect(RemoteStatisticService remoteStatisticService) {
        this.remoteStatisticService = remoteStatisticService;
    }
....
}

I tried to use normal injection like private @Inject RemoteStatisticService remoteStatisticService; but it gave me error of NullPointerException.

Any help is appreciated. Thanks

Ihsan Haikal
  • 1,085
  • 4
  • 16
  • 42
  • You need a no-arg constructor for the aspect. Dependency injection doesn't work on aspects, you need to inject manually at app startup. See my [answer](http://stackoverflow.com/a/36049252/2699901) on a similar question. It's not the accepted answer but I consider it more simple than the accepted answer which uses inter-type declarations and requires that the advised beans must be managed too, which is not a requirement in my answer. – Nándor Előd Fekete May 20 '16 at 02:29
  • @NándorElődFekete thank you for the suggestion but in this case of GreeterAspect.aspectOf().setGreeter(greeter); to be implemented in my case couldn't think of similar solution as I am injecting an interface class and I believe it's impossible to make getter and setter of an interface class. Also the method aspectOf() does not exist in my package, maybe because I'm using annotation instead of pure AspectJ implementation of aspect class? CMIIW – Ihsan Haikal May 20 '16 at 08:14
  • @NándorElődFekete i actually thought of using a "third party" class that instead of injecting the interface to the aspect I will inject the interface into this class but still NullPointerException error. Maybe you could help to look into that [here](http://stackoverflow.com/questions/37319528/injection-error-nullpointerexception-for-aspectj-annotation-class-java) Thanks – Ihsan Haikal May 20 '16 at 08:26
  • You can make setter and getter for interfaces, it doesn't matter, it's just a type. I missed the part where you said it's AspectJ annotation style, so I'll provide a quick answer here. – Nándor Előd Fekete May 20 '16 at 10:55

2 Answers2

2

Aspects are not candidates for dependency injection, so you'll have to work around this limitation. They're also instantiated by the aspectj runtime, and not CDI, and you can't take control of their instantiation.

What you can do is, create a separate class which is handled by the CDI container and inject the aspect's dependencies into this helper class instead. Then set up your aspect's dependencies from this helper class manually. You can mark this helper class as a startup singleton, so that it runs at startup after it's dependencies can be satisfied.

You could use a startup singleton helper bean similar to this one:

@Singleton
@Startup
public class MeasurementAspectSetup {

    @Inject
    private RemoteStatisticService remoteStatisticService;

    @PostConstruct
    private void setupAspect() {
        Aspects.aspectOf(MeasurementAspect.class)
            .setRemoteStatisticService(this.remoteStatisticService);
    }

}

Of course, you would have to add the setter for the RemoteStatisticService to the aspect, or change the field's visibility in the aspect and set it directly. You'll also need to remove the parametric constructor from the aspect so a default no-arg constructor is available.

Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47
  • in this case should I inject or initiate the interface RemoteStatisticService into MeasurementAspect class? – Ihsan Haikal May 20 '16 at 13:13
  • I have tried your code with the injection of interface RemoteStatisticService into the MeasurementAspect but still NullPointerException error. [Here](http://pastebin.com/UMWgDvgg) is the code to the MeasurementAspect class (only excerpt as it is too long) – Ihsan Haikal May 20 '16 at 13:36
  • Create a singleton startup bean similar to the one in my answer. Place a debug breakpoint in the `setupAspect()` method and check what happens at application startup. It should stop in that method and you should use that method to set up your aspects dependencies. After the method finished, your aspect should be ready to run. You could use a boolean flag in your aspect to indicate that setup is completed, and check its value at runtime so that your aspect won't try to run before it's set up completed. – Nándor Előd Fekete May 20 '16 at 13:49
  • @ NándorElődFeketeI actually already tried to create a separate class that I can use to inject the interface and Aspect class will only need to instantiate this class, you could see my another question [here](http://stackoverflow.com/questions/37343280/injection-cdi-of-interface-returns-nullpointerexception/37343831#37343831) but the problem is still NullPointerException for dependency injection – Ihsan Haikal May 20 '16 at 13:56
  • This answer doesn't try to solve your simple CDI problems. It only tries to solve the problem of setting up aspect dependencies in a CDI environment. In order for it to work it needs a working CDI setup. If the `remoteStatisticService` field doesn't get injected in the `MeasurementAspectSetup` helper class it means you need to solve that problem first. You're probably missing an implementation of the `RemoteStatisticService` interface. – Nándor Előd Fekete May 20 '16 at 14:07
  • as far as I know it is implemented properly [here](http://pastebin.com/gxMDg4x6) but the problem is still the injection still always return null so I am not sure what's going on – Ihsan Haikal May 20 '16 at 15:03
  • I'm not really familiar with CDI, but shouldn't it be `@Local` or even `@Stateless` instead of `@LocalBean`? `@LocalBean` seems to indicate the bean should provide a no-interface view, which seems to be contrary to your intention. – Nándor Előd Fekete May 20 '16 at 18:03
  • Sorry for replying late. I actually tried your answer several times but it gave me error of NullPointerException. So [here](http://pastebin.com/Ws9LzS8M) is the aspect class of MeasurementAspect.class and [here]( http://pastebin.com/66SLF1pW) is the MeasurementAspectSetup class. I think the MeasurementAspectSetup class is not triggered automatically when the app starts and I tried to instantiate it but still it is not triggered. Could you take a look into the code? Thanks – Ihsan Haikal May 27 '16 at 08:17
1

@Nándor Előd Fekete's answer above lead me to a similar solution using more modern annotations and constructor injection:

@Component
public class MeasurementAspectSetup {

    private RemoteStatisticService remoteStatisticService;

    MeasurementAspectSetup(RemoteStatisticService remoteStatisticService) {
        this.remoteStatisticService = remoteStatisticService;
    }

    @PostConstruct
    private void setupAspect() {
        Aspects.aspectOf(MeasurementAspect.class)
            .setRemoteStatisticService(this.remoteStatisticService);
    }

}

I hope an update of the solution a few years later helps someone else!

cptully
  • 615
  • 1
  • 9
  • 24