This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
#AspectJ pointcut for all methods of a class with specific annotation
I am trying to write a pointcut for all methods of a class which have a custom annotation. Here's the code
Annotation:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(value = RetentionPolicy.RUNTIME)
#Target(value = ElementType.METHOD)
public #interface ValidateRequest {}
Method in Controller:
#RequestMapping(value = "getAbyB", produces = "application/json")
#ResponseBody
#ValidateRequest
public Object getAbyB(#RequestBody GetAbyBRequest req) throws Exception {
/// logic
}
Aspect:
#Aspect
#Component
public class CustomAspectHandler {
#Before("execution(public * *(..))")
public void foo(JoinPoint joinPoint) throws Throwable {
LOG.info("yippee!");
}
}
applicationContext:
`<aop:aspectj-autoproxy />`
I've been trying various advices, mentioned below, but none seem to work (except for the one used above)
#Around("#within(com.pack.Anno1) || #annotation(com.pack.Anno1)")
#Around("execution(#com.pack.Anno1 * *(..))")
This should work:
#Aspect
#Component
public class CustomAspectHandler {
#Pointcut("execution(#ValidateRequest * *.*(..))")
public void validateRequestTargets(){}
#Around("validateRequestTargets()")
public Object foo(JoinPoint joinPoint) throws Throwable {
LOG.info("yippee!");
return joinPoint.proceed();
}
}
Related
When trying to use #AutoWire feature with one of StandAlone Application unable to do so instead getting Null Pointer Exception. Please highlight my mistakes if any. Your help is appreciated.
Spring Ver 5.1.5.RELEASE and we're not using any xml config file to tell spring there are annotated classes to look into instead using #ComponentScan or #EnableAutoConfiguration at the top of AppConfig and boost strap the Context from main() class as a first line. But Autowiring works perfectly with internal bean/java classes of jdk(Environment) but not with custom POJO classes. If we're trying to get through getBean method then it works. But I'm trying to avoid creating context everywhere and using getBean() Please Refer below and help me only with your valuable guidelines.
public class ContextMaster {
private static AnnotationConfigApplicationContext appContext;
public static AnnotationConfigApplicationContext getApplicationContext() {
if (appContext == null) {
appContext = new AnnotationConfigApplicationContext(ContextConfig.class);
//appContext = new AnnotationConfigApplicationContext("com.xx.xx.xxx","xx.xxx.xxxx.xxx.datamanager");
logger.debug("Context Invoked !!");
}
return appContext;
}
}
#Configuration
#EnableAutoConfiguration
#PropertySource("classpath:db.properties")
#EnableTransactionManagement
#ComponentScans(value = {
#ComponentScan(basePackages = "xxxxx.datamanager"),
#ComponentScan(basePackages = "com.xx.xx.xxx"),
#ComponentScan(basePackages = "com.xx.xx.xxx.utils")})
public class AppConfig {
#Autowired
private Environment env;
#Bean
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
return dataSource;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
//LocalSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
factoryBean.setDataSource(getDataSource());
Properties props=new Properties();
props.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
props.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
props.put("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
factoryBean.setHibernateProperties(props);
factoryBean.setAnnotatedClasses(xx.class, xxxx.class, xxxx.class, xxx.class);
return factoryBean;
}
#Bean
public HibernateTransactionManager getTransactionManager() {
return transactionManager;
}
}
// Here is NPE thrown when tried with auto-configured bean
#Component
public class Good extends Good11 {
#Autowired
private RxxxDyyyyHelper rdh;
//RxxxDyyyyHelper rdh =
ContextHelper.getApplicationContext().getBean(RxxxDyyyyHelper .class);
rdh.setProperty(); // NPE here
rdh.getProperty(); // NPE
}
// Here we're trying to initiate the LosUtils class
public class LosUtils {
public static void main(String args[]) throws Exception {
AnnotationConfigApplicationContext applicationContext = `ContextHelper.getApplicationContext();`
}
It seems like you didn't put the full code here, because your Good class won't compile this way..
I use AtomicLongMap in the construct function of RichMapFunctin.Like
public class PathAnalysis extends RichMapFunction<ApiLog, ApiLog> {
private final AtomicLongMap<Object> mObjectAtomicLongMap;
public PathAnalysis()
{
mObjectAtomicLongMap = AtomicLongMap.create();
}
}
register the custom serizlize class, but it not work
env.getConfig().registerTypeWithKryoSerializer(AtomicLongMap.class, new AtomicLongMapSerializer());
It cause:
org.apache.flink.api.common.InvalidProgramException: The implementation of the RichMapFunction is not serializable. The object probably contains or references non serializable fields.
at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:99)
at org.apache.flink.streaming.api.environment.StreamExecutionEnvironment.clean(StreamExecutionEnvironment.java:1550)
at org.apache.flink.streaming.api.datastream.DataStream.clean(DataStream.java:184)
at org.apache.flink.streaming.api.datastream.DataStream.map(DataStream.java:528)
at com.ghzs.Topology.main(Topology.java:91)
Caused by: java.io.NotSerializableException: org.apache.flink.shaded.curator.org.apache.curator.shaded.com.google.common.util.concurrent.AtomicLongMap
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.apache.flink.util.InstantiationUtil.serializeObject(InstantiationUtil.java:315)
at org.apache.flink.api.java.ClosureCleaner.clean(ClosureCleaner.java:81)
... 4 more
AtomicLongMap is not implements of Serializable .How can I register a effective custom serialize method?
Mark AtomicLongMap as transient, and allocate it in the open() call that your function will receive (because it's a RichMapFunction). So something like:
public class PathAnalysis extends RichMapFunction<ApiLog, ApiLog> {
private transient AtomicLongMap<Object> mObjectAtomicLongMap;
public PathAnalysis() { }
#Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
mObjectAtomicLongMap = AtomicLongMap.create();
}
}
try with implementation of this function like:
import org.apache.flink.api.common.functions.RichMapFunction;
import com.google.common.util.concurrent.AtomicLongMap;
public class PathAnalysis extends RichMapFunction<ApiLog, ApiLog> {
private final AtomicLongMap<Object> mObjectAtomicLongMap;
public PathAnalysis()
{
mObjectAtomicLongMap = AtomicLongMap.create();
}
#Override
public ApiLog map(ApiLog value) throws Exception {
// TODO Auto-generated method stub
return null;
}
}
I am trying to come up with an easy to use CDI way to use properties. Based on several blogs this is the (not working) result (sorry for the layout cannot get that right).
1. EEProperties (the provider, seperate jar):
#Singleton
public class EEProperties extends AbstractPropertiesDecorator {
#Inject
public EEProperties(#InjectInEEProperties EnhancedMap properties) {
super(properties);
}
private String[] getKeys(final InjectionPoint ip) {
return (ip.getAnnotated().isAnnotationPresent(Property.class) && ip.getAnnotated().getAnnotation(Property.class).keys().length>0) ?
ip.getAnnotated().getAnnotation(Property.class).keys() :
new String[] {ip.getMember().getName()};
}
#Produces
#Property
public File[] getFileProperties(InjectionPoint ip) {
return getFileProperties(null, getKeys(ip));
}
}
2. A ManagedBean consumer (in war):
#Inject
#Property(keys = {"test"})
private String test;
3. ...that also produces the constructor argument for the provider:
#Produces
#InjectInEEProperties
public EnhancedMap getP() {
EnhancedMap m = new Settings();
m.put("test", "cdi works");
return m;
}
4. annotation for cdi container:
#Qualifier
#Retention(RUNTIME)
#Target({FIELD,ElementType.METHOD,ElementType.PARAMETER})
public #interface InjectInEEProperties {
#Nonbinding String key() default "";
}
5. annotation for consumer:
#Qualifier
#Retention(RUNTIME)
#Target({FIELD,ElementType.METHOD})
public #interface Property {
#Nonbinding String[] keys() default {};
}
6. problem when running this (on payara 5):
Caused by: java.lang.NullPointerException at
org.glassfish.weld.services.JCDIServiceImpl.createManagedObject(JCDIServiceImpl.java:463)
at
org.glassfish.weld.services.JCDIServiceImpl.createManagedObject(JCDIServiceImpl.java:314)
at
com.sun.enterprise.container.common.impl.managedbean.ManagedBeanManagerImpl.createManagedBean(ManagedBeanManagerImpl.java:476)
I've tried a lot of things, but cannot get this to work, including removing the #Produces from the ManagedBean.
Solved the issue by creating a seperate class responsible for providing constructor argument:
#Singleton
public class PP {
#Produces
#InjectInEEProperties
public EnhancedMap getP() {
EnhancedMap m = new Settings();
m.put("test", "cdi works");
return m;
}
}
For some reason I can't work out yet, my agent doesn't intercept java LinkageError instances.
Agent code:
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
public class MyAgent {
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.isSubTypeOf(LinkageError.class))
.transform((builder, type, classLoader, module) ->
builder.constructor(ElementMatchers.isDefaultConstructor())
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(MyInterceptor.class)))
).installOn(instrumentation);
}
}
Interceptor code:
public class MyInterceptor {
#RuntimeType
public static void intercept(#Origin Constructor<?> constructor) throws Exception {
System.out.println("Intercepted: " + constructor.getName());
}
}
Test code:
public static void main(String[] args) {
new NoClassDefFoundError("should be intercepted!!!").toString();
new Foo("oh").toString();
}
What is puzzling is that replacing ElementMatchers.isSubTypeOf(LinkageError.class) with ElementMatchers.nameContains("Foo") gives the expected result and Foo constructor is intercepted.
The NoClassDefFoundError is loaded by the bootstrap loader. It willnot be able to see your interceptor class which is why it is never triggered.
Try using the Advice class (as a visitor) to add bytecode to matched classes which should resolve this problem.
#Before(value="#annotation(com.aspect.Loggable)",argNames="taskId")
public void logEmail(JoinPoint joinPoint) {
System.out.println("#Before is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}
i have a pointCut on method sendEmail() with custom annotation.
This method sendEmail() is called from differnt location in our application .
Like we call sendEmail from paymentApproved () method of paymentManager when payment is approved.
We call sendEmail from taskComplete() method of taskManger when task is completed.
i have to find out the event for which sendEmail is triggered.
I applied custom annotation #EVENT("PAYMENT") on paymentApproved () of paymentManager and #EVENT("TASK") on taskComplete() method of taskManger.
How can i get the value of #EVENT in logEmail(JoinPoint joinPoint) aspect.
Scaffolding:
Sorry, I do not like all-caps class names and I also used my own package names as an example because my template already generates them.
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Loggable {}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Event {
String value();
}
Driver application:
This is pure Java because I am not a Spring user. Just imagine it is one or more #Components.
Please also note that in one case sendEmail() is called from a method not annotated by #Event. This should not trigger the aspect, only the two calls from the annotated methods.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.doSomething();
application.paymentApproved();
application.taskComplete();
}
public void doSomething() {
sendEmail();
}
#Event("paymentApproved")
public void paymentApproved() {
sendEmail();
}
#Event("taskComplete")
public void taskComplete() {
sendEmail();
}
#Loggable
public void sendEmail() {}
}
Aspect:
Your pointcut wants to express: Catch methods annotated with #Loggable within the control flow of methods annotated by #Event. Control flow can be expressed by cflow() or cflowbelow() pointcuts.
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import de.scrum_master.app.Event;
#Aspect
public class LogAspect {
#Before(
"#annotation(de.scrum_master.app.Loggable) &&" +
"execution(* *(..)) &&" + // only needed for AspectJ, not for Spring AOP
"cflow(#annotation(event))"
)
public void logEmail(JoinPoint thisJoinPoint, Event event) {
System.out.println(thisJoinPoint + " -> " + event);
}
}
Console log:
execution(void de.scrum_master.app.Application.sendEmail()) -> #de.scrum_master.app.Event(value=paymentApproved)
execution(void de.scrum_master.app.Application.sendEmail()) -> #de.scrum_master.app.Event(value=taskComplete)
Update: If you were using full AspectJ (e.g. via load-time weaving) instead of Spring AOP, you just could have used a call() pointcut and from there get the enclosing joinpoint's static information. Then the #Event annotation would not have been necessary. But Spring AOP is just "AOP lite" and does not support call().
You can access to the annotation receiving it as a parameter. Something like this:
#Before(value="#annotation(EVENT)",argNames="taskId")
public void logEmail(JoinPoint joinPoint, Event event) {
// do what you need with event. For example, if the field is called value you can do this:
if ("PAYMENT".equals(event.value())) {
// do sth
}
System.out.println("#Before is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}