Lets say I have the following code:
package util;
interface Function {
public void call(Object... args);
}
OR
package util;
class Function {
public void call(Object... args){};
}
And this is how I use said interface or class:
Function onComplete = new Function() {
#Override
public void call(final Object... args) {
...
}
}
What I want to do with aspectj is trace the "new Function" -- but it does not work
#AfterReturning("call(util.Function.new())")
This Pointcut above does not work.
Any help or insights would be much appreciated.
Thank you.
Ok, sure.
This is the answer.
#AfterReturning("call(util.Function+.new())")
The "+" indicates to match any sub-classes of Function as well as Function itself.
Where as
#AfterReturning("call(util.Function.new())")
Is strictly going to match Function class only.
That is my understanding from reading the docs.
Related
I'm a newbie to AspectJ, and trying to understand joinpoint model
Now i have class like this
public class Account {
private static Map<String, PaymentMethod> supportedPayments = new HashMap<>();
static {
supportedPayments.add("COD", new CodPaymentMethod());
supportedPayments.add("ATM", new ATMPaymentMethod());
}
}
as i read from AspectJ In Action, there is a way to define pointcut when class is intialization, but i could not find syntax.
Anyone help me?
This one does not work:
#Pointcut("initialization(com.jas.aop.bean.Payment"))
it say
ERROR] Syntax error on token "initialization(com.jas.aop.bean.Payment)", "name pattern" expected
/Users/admin/eclipse-workspace/aop/src/main/java/com/jas/aop/aspect/ClassInitializationAspect.java:9
#Pointcut("initialization(com.jas.aop.bean.Payment)")
Your pointcut has several problems:
There is a missing closing parenthesis ).
initialization intercepts constructors (i.e. object initialisation) rather than static class initialisation, which is not what you want and also would require a constructor pattern, not a class name pattern.
If your aspect does not happen to be in the exact same package as the target class, you must use a fully qualified class name such as my.package.Account in order to make the pointcut match.
By the way, your code snippets are just pseudo code because a hash map does not have an add method, rather a put method. The sample class does not even compile. Don't just invent code when posting questions here. Make life easier for the people trying to help you.
Now here is an MCVE, something I always suggest you to specify in your question in order to help people reproduce your situation. I did it for you this time, this was your free shot. Next time, please do it yourself.
Dependency classes used by the main class:
package de.scrum_master.app;
public interface PaymentMethod {}
package de.scrum_master.app;
public class ATMPaymentMethod implements PaymentMethod {}
package de.scrum_master.app;
public class CodPaymentMethod implements PaymentMethod {}
Target class with driver application:
package de.scrum_master.app;
import java.util.HashMap;
import java.util.Map;
public class Account {
private static Map<String, PaymentMethod> supportedPayments = new HashMap<>();
static {
System.out.println("Static initialiser block");
supportedPayments.put("COD", new CodPaymentMethod());
supportedPayments.put("ATM", new ATMPaymentMethod());
}
public Account() {
System.out.println("Creating account");
}
public void doSomething() {
System.out.println("Doing something");
}
public static void main(String[] args) {
new Account().doSomething();
}
}
Aspect:
The aspect shows both initialization and staticinitialization in order to show the difference in both syntax and functionality. You can find all of this explained with examples in the AspectJ manual, which I warmly recommend you to read.
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class AccountAspect {
#Before("initialization(de.scrum_master.app.Account.new(..))")
public void interceptObjectInitialisation(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
#Before("staticinitialization(de.scrum_master.app.Account)")
public void interceptClassInitialisation(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
}
Console log:
staticinitialization(de.scrum_master.app.Account.<clinit>)
Static initialiser block
initialization(de.scrum_master.app.Account())
Creating account
Doing something
What I am trying to do is wrap a decorator around a command using the following code.
public interface ICommand
{
}
public interface ICommand<T> : ICommand where T : class
{
void Execute(T args);
}
public class TransactionalCommand<T> : ICommand<T>
where T : class
{
private readonly ICommand<T> command;
public TransactionalCommand(ICommand<T> command)
{
this.command = command;
}
public void Execute(T args)
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
this.command.Execute(args);
scope.Complete();
}
}
}
Here is how I am invoking the resolve but i only get back my ChangePasswordCommand without the decoratoration. (Actually it wont event compile on the second Bind)
The ultimate goal is to have this auto-register all my types using this decorator. Any help would be great!
Bind<ChangePasswordCommand>().To<ChangePasswordCommand>()
.WhenInjectedInto<TransactionalCommand<ChangePasswordArgs>>();
Bind<ChangePasswordCommand>().To<TransactionalCommand<ChangePasswordArgs>>()
.InTransientScope();
var command = kernel.Get<ChangePasswordCommand>();
You were pretty close. However: when you want to use a decorator you need the decorator to implement the same interface as the command. That's the case here, but you'll also need to resolve that interface (and bind it, too). So here's how it works:
kernel.Bind<ICommand<ChangePasswordArgs>>().To<ChangePasswordCommand>()
.WhenInjectedInto<TransactionalCommand<ChangePasswordArgs>>();
kernel.Bind<ICommand<ChangePasswordArgs>>().To<TransactionalCommand<ChangePasswordArgs>>()
.InTransientScope();
var command = kernel.Get<ICommand<ChangePasswordArgs>>();
I'd like to inject a dependency into an NServiceBus Message Mutator... since the lifetime of the Mutators is controlled by NServiceBus (and NSB wants a paramaterless constructor), constructor injection won't work...
any ideas?
UPDATE: Here is the code:
public class AddTransactionInformationToOutgoingHeaders :
IMutateOutgoingTransportMessages,
INeedInitialization
{
private readonly IProvideTransactionInformation transactionInformationProvider;
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<AddTransactionInformationToOutgoingHeaders>(DependencyLifecycle.InstancePerCall);
}
public AddTransactionInformationToOutgoingHeaders()
{
}
public AddTransactionInformationToOutgoingHeaders(IProvideTransactionInformation transactionInformationProvider)
{
this.transactionInformationProvider = transactionInformationProvider;
}
public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
{
...
}
}
}
If I take away the empty ctor, I get this error message thrown from my ConfigureBus() call in Global.asax:
"No parameterless constructor defined for this object."
To get around this, I just kept one empty constructor for NServiceBus and then created a overloaded constructor that took my dependency that is managed by Unity.
It works.
Didn't know that mutators could work like that. It was my first time trying to inject a dependency into one.
UPDATE:
I got around this by using property injection on the mutator instead:
public class AddTransactionInformationToOutgoingHeaders : IMutateOutgoingTransportMessages, INeedInitialization
{
public IProvideTransactionInformation TransactionInformationProvider { get; set; }
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<AddTransactionInformationToOutgoingHeaders>(DependencyLifecycle.InstancePerCall);
}
public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
{
...
}
}
Worked perfectly.
Pretty sure both constructor and property injection should work. What is the exception?
New poster here, hope I don't brake any rules :)
I am using PrivateModule in google-guice in order to have multiple DataSource's for the same environment. But I am having a hard time getting MethodInterceptor's to work inside the private modules.
Below is a simple test case that explains the "problem".
A simple service class would be:
interface Service {
String go();
}
class ServiceImpl implements Service {
#Override #Transactional
public String go() {
return "Test Case...";
}
}
The MyModule class would be:
class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new PrivateModule() {
#Override
protected void configure() {
bind(Service.class).to(ServiceImpl.class);
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(Transactional.class),
new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation i)
throws Throwable {
System.out.println("Intercepting: "
+ i.getMethod().getName());
return i.proceed();
}
});
expose(Service.class);
}
});
}
}
And the final test case:
public class TestCase {
#Inject Service service;
public TestCase() {
Guice.createInjector(new MyModule()).injectMembers(this);
}
public String go() {
return service.go();
}
public static void main(String[] args) {
TestCase t = new TestCase();
System.out.println(t.go());
}
}
You would expect the output to be:
Intercepting: go
Test Case...
But it doesn't happen, the interceptor is not used, ant only Test Case... is output.
If I bind/expose the ServiceImpl instead of the interface then it works.
Thanks in advance,
Regards,
LL
Well... I figured it out shortly after I posted the question :)
The problem is that you also need to expose() the ServiceImpl class.
So the bind/expose would be.
bind(ServiceImpl.class); // ServiceImpl annotated with #Singleton
bind(Service.class).to(ServiceImpl.class);
expose(ServiceImpl.class);
expose(Service.class);
Regards,
LL
You need to explicitly bind ServiceImpl in the private module. The problem with your existing code is that it inherits the binding for ServiceImpl from the parent module. From the PrivateModule docs,
Private modules are implemented using parent injectors. When it can satisfy their dependencies, just-in-time bindings will be created in the root environment. Such bindings are shared among all environments in the tree.
Adding this line should fix the problem:
bind(ServiceImpl.class);
I have 2 classes that have the exact same logic/workflow, except in one method.
So, I created a abstract base class where the method that differs is declared as abstract.
Below is some sample code to demonstrate my design; can anyone offer suggestions on a better approach or am I heading in the right direction.
I didn't use an interface because both derived classes B and C literally share most of the logic. Is there a better way to do what I am doing below via dependency injection?
public abstract class A
{
public void StageData()
{
// some logic
DoSomething();
}
public void TransformData();
public abstract DoSomething();
}
public class B : A
{
public override void DoSomething()
{
// Do Something!
}
}
public class C : A
{
public override void DoSomething()
{
// Do Something!
}
}
There is nothing wrong with what you have done. To introduce dependency injection into this design would be messy and overkill - you would have to pass in a delegate:
public class ABC
{
public ABC(Action z)
{
_doSomethingAction = z;
}
public void DoSomething()
{
_doSomthingAction.Invoke();
}
private Action _doSomthingAction;
}
There would be few reasons why you want to use this approach - one would be if you needed to execute a callback. So stick with the pattern you have, don't try to overcomplicate things.