Spring 3.2 AOP - Intercepting methods by annotation - spring

I'm trying to intercept any method tagged w/ a custom annotation and the reason you read this is because I can't get it to work. I've been following simple examples but can't get it to work.
Here is my code.
MyAnnotation.java:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {
String value() default "";
String key() default "";
String condition() default "";
}
MyAspect.java:
#Aspect
public class MyAspect {
#Pointcut(value="execution(public * *(..))")
public void anyPublicMethod() { }
#Around("anyPublicMethod() && #annotation(myAnnotation)")
public Object process(ProceedingJoinPoint jointPoint, MyAnnotation myAnnotation) throws Throwable {
System.out.println("In AOP process");
return 5; //jointPoint.proceed();
}
}
spring-config.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd">
...
<context:component-scan base-package="com.myapp">
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="myAspect" class="com.myapp.annotation.MyAspect" />
...
MyComponent.java:
#Component
public class MyComponent {
#MyAnnotation(value="valtest", key="keytest", condition="contest")
public int add(int i, int j) {
System.out.println("Executing annotation.add");
return i+j;
}
}
Test code:
final MyComponent m = new MyComponent();
assertTrue(5 == m.add(0, 1)); // Here m.add(...) always returns 1 instead of 5.
As a side note I've tried to define my pointcut many different ways, all with and without the use of the anyPublic() method and its execution pointcut, but none of those worked for me:
#Around("#annotation(com.myapp.annotation.MyAnnotation)")
public Object process(ProceedingJoinPoint jointPoint) throws Throwable { .. }
#Around(value="#annotation(myAnnotation)", argNames="myAnnotation")
public Object process(ProceedingJoinPoint jointPoint, MyAnnotation myAnnotation) throws Throwable { .. }
#Around("execution(* com.myapp.*.*(..)) && #annotation(com.myapp.annotation.MyAnnotation)")
public Object process(ProceedingJoinPoint jointPoint) throws Throwable { .. }
What am I doing wrong?

In your test code, you are not allowing Spring to create your MyComponent, but instead, you are using the new operator. You should be accessing MyComponent from Spring's ApplicationContext.
public class SomeTest {
public static void main(String[] args) throws Exception {
final ApplicationContext appContext = new ClassPathXmlApplicationContext("spring-config.xml");
final MyComponent myComponent = appContext.getBean(MyComponent.class);
//your test here...
}
}
If you do not get your component from Spring, how do you expect it to be proxied?

Related

spring aop logging advice is not getting called

I am writing simple aspect with simple logging advice which will be called upon setter of class.
Below is code Snippet
AopMain.java
package com.example.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.test.model.Triangle;
import com.example.test.service.ShapeService;
public class AopMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//ShapeService shapeService = context.getBean("shapeService", ShapeService.class);
//shapeService.getTriangle().setName("triangle");
Triangle triangle = new Triangle();
triangle.setName("triangle class");
System.out.println(triangle.getName());
}
}
Triangle.java
package com.example.test.model;
public class Triangle {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println(name);
}
}
LoggingAspect.java
package com.example.test.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import com.example.test.model.Triangle;
#Component
#Aspect
public class LoggingAspect {
#Before("execution(public * *(..))")
public void LoggingAdvice(JoinPoint jPoint) {
System.out.println("Advice run. Get method is called " + jPoint.getTarget());
Triangle triangle = (Triangle) jPoint.getTarget();
}
#Before("args(name)")
public void test(String name) {
System.out.println("logging advice args " + name);
}
}
Output
triangle class
triangle class
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<!-- <bean id="triangle" class="com.example.test.model.Triangle">
<property name="name" value="Triangle Name"></property>
</bean> -->
<bean id="circle" class="com.example.test.model.Circle">
<property name="name" value="Circle Name"></property>
</bean>
<bean id="shapeService"
class="com.example.test.service.ShapeService" autowire="byType" />
<aop:aspectj-autoproxy />
<context:component-scan
base-package="com.example.test" />
</beans>
spring is working properly.
I do not understand why aspect is not gettting called.
please help me to understand this issue.

Issue when executing spring bean

I've a bean named textFileWriter to write string entities to HDFS. I've configured the spring bean in bean config file. While executing am getting NullPointerException. Please help me on this.
My bean configuration :-
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/hadoop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:hdp="http://www.springframework.org/schema/hadoop" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/hadoop http://www.springframework.org/schema/hadoop/spring-hadoop.xsd">
<hdp:configuration id="hadoopConfigBean">
fs.defaultFS=${hdp.fs}
</hdp:configuration>
<beans:bean id="textFileWriter"
class="org.springframework.data.hadoop.store.output.TextFileWriter">
<beans:constructor-arg index="0" ref="hadoopConfigBean"></beans:constructor-arg>
<beans:constructor-arg index="1"
type="org.apache.hadoop.fs.Path" value="/user/mhduser"></beans:constructor-arg>
<beans:constructor-arg index="2" type="org.springframework.data.hadoop.store.codec.CodecInfo" >
<beans:null></beans:null>
</beans:constructor-arg>
</beans:bean>
<context:property-placeholder location="hadoop-configs.properties" />
</beans:beans>
Main Class :-
public class MainApp {
#Autowired
TextFileWriter textFileWriter;
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/spring/application-context.xml", MainApp.class);
System.out.println("Context loaded...");
MainApp obj=new MainApp();
obj.someMethod();
context.registerShutdownHook();
}
private void someMethod() {
try {
textFileWriter.write("hi there");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Am getting null pointer exception in this line :-
textFileWriter.write("hi there");
You can still make Spring inject dependencies without adding MainApp as a bean explicitly.
Enable annotation driven config. Add to the application-context.xml following
<context:annotation-config />
Make Spring wire dependencies with
MainApp obj=new MainApp();
context.getAutowireCapableBeanFactory().autowireBean(obj);
#Autowired won't work here because you are using a new instance of class MainApp which is not managed by spring and that's why you are getting a NullPointerException
MainApp obj=new MainApp();
obj.someMethod();
A work around would be :
public class MainApp {
public MainApp(TextFileWriter textFileWriter){
this.textFileWriter = textFileWriter;
}
public MainApp(){
}
#Autowired
TextFileWriter textFileWriter;
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/spring/application-context.xml");
System.out.println("Context loaded...");
TextFileWriter textFileWriter = (TextFileWriter ) context.getBean("textFileWriter");
MainApp obj=new MainApp(textFileWriter );
obj.someMethod();
context.registerShutdownHook();
}
private void someMethod() {
try {
textFileWriter.write("hi there");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

javax.persistence.TransactionRequiredException

I am getting the below error, I have gone through all of the similar issues, but don't able to figure out where I am going wrong.
Here is the error:
Exception in thread "main" javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:275)
at com.sun.proxy.$Proxy19.persist(Unknown Source)
at com.project.vibhas.dao.hibernate.GenericDaoJpa.save(GenericDaoJpa.java:45)
at com.project.vibhas.service.impl.PersonServiceImpl.save(PersonServiceImpl.java:22)
at com.project.vibhas.domain.App.main(App.java:25)
Here are my code:
package com.project.vibhas.dao.hibernate;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
import com.project.vibhas.dao.GenericDao;
import com.project.vibhas.domain.DomainObject;
public class GenericDaoJpa<T extends DomainObject> implements GenericDao<T> {
private Class<T> type;
protected EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public GenericDaoJpa(Class<T> type) {
super();
this.type = type;
}
#Transactional
public void save(T object) {
System.out.println("inside generic dao");
entityManager.persist(object);
}
public void delete(T object) {
entityManager.remove(object);
}
}
My Dao class:
#Repository("personDao")
public class PersonDaoJpa extends GenericDaoJpa<Person> implements PersonDao {
public PersonDaoJpa() {
super(Person.class);
}
public Person authenticatePerson(String username, String password)
throws DataAccessException, AuthenticationException {
List<Person> results = null;
Query query = entityManager
.createQuery("from Person as p where p.username = :username and p.password = :password");
query.setParameter("username", username);
query.setParameter("password", password);
results = query.getResultList();
if (results == null || results.size() <= 0) {
throw new AuthenticationException("No users found");
} else {
return results.get(0);
}
}
public Person getPersonByUsername(String username)
throws DataAccessException, EntityNotFoundException {
List<Person> results = null;
Query query = entityManager
.createQuery("from Person as p where p.username = :username");
query.setParameter("username", username);
results = query.getResultList();
if (results == null || results.size() <= 0) {
throw new EntityNotFoundException(username + " not found");
} else {
return results.get(0);
}
}
}
My sercice Class:
package com.project.vibhas.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.project.vibhas.dao.PersonDao;
import com.project.vibhas.domain.Person;
import com.project.vibhas.service.PersonService;
#Service("personService")
public class PersonServiceImpl implements PersonService{
#Autowired
PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
public void save(Person person) {
System.out.println("Inside service");
//personDao.get(1L);
personDao.save(person);
}
}
My Test Class:
package com.project.vibhas.domain;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.project.vibhas.service.PersonService;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext(
"classpath*:META-INF/spring/spring-jpa.xml");
PersonService personService = (PersonService) appContext.getBean("personService");
Person person = new Person();
person.setId(1L);
personService.save(person);
System.out.println("Done");
}
}
Spring-Jpa.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- The rest of the config is covered below -->
<context:annotation-config />
<context:spring-configured />
<context:component-scan base-package="com.project" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="org.postgresql.Driver"
p:url="jdbc:postgresql://localhost:5433/mypostgresdb"
p:username="postgres"
p:password="root" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" />
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
</beans>
Persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="galleryPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<!--
value='create' to build a new database on each run;
value='update' to modify an existing database;
value='create-drop' to create and drop tables on each run;
value='validate' makes no changes to the database
-->
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>

Spring + Hibernate + DAO + SessionFactory + Inject

I use Spring with Hibernate and get always a NPE for the sessionFactory Object.
My config file:
#Configuration
public class HibernateConfiguration {
#Bean
public AnnotationSessionFactoryBean sessionFactory() {
Properties props = new Properties();
props.put("hibernate.dialect", MySQL5InnoDBDialect.class.getName());
props.put("hibernate.format_sql", "true");
props.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
props.put("hibernate.connection.password", "xxx");
props.put("hibernate.connection.url", "jdbc:mysql://localhost/Market");
props.put("hibernate.connection.username", "philipp");
AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();
bean.setAnnotatedClasses(new Class[] { xxx.class, xxx.class, xxx.class });
bean.setHibernateProperties(props);
bean.setSchemaUpdate(true);
return bean;
}
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
#Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
My DAOImpl class:
#Repository("xxx")
public class xxxDAOImpl implements xxxDAO {
private SessionFactory sessionFactory;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
...
Testcase:
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class TestxxxDAOImpl {
#Test
#Transactional
public void testInsertxxx() throws Exception {
xxxDAO xxxDAO = new xxxDAOImpl();
xyz xyz = new xyz();
xxxDAO.insert(xyz);
assertNotNull(xyz.getId());
}
}
app-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="xxx.config" />
<context:component-scan base-package="xxx.dao" />
<context:annotation-config></context:annotation-config>
test-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath:/META-INF/spring/app-context.xml" />
I get always an NPE from the currentSession when the test calls the insert method.
public void insert(xxx xxx) {
currentSession().save(xxx);
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
The very first thing to understand when working with Spring is that Spring dependency injection only works for beans obtained from the application context, not for beans created with new.
In Spring-enabled unit tests you configure application context using #ContextConfiguration, for example, as follows (works in Spring 3.1, in previous versions #ContextConfiguration doesn't take #Configuration classes directly, therefore you'll have to create XML configuration file):
#Configuration
public class HibernateConfiguration {
// Add your DAO to application context
#Bean
public xxxDAO xxxDAO() {
return new xxxDAOImpl();
}
...
}
// Configure application context using the given #Configuration class
#ContextConfiguration(classes = HibernateConfiguration.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class TestxxxDAOImpl {
// Obtain DAO from the application context
#Autowired xxxDao xxxDao;
...
}
Instead of sessionFactory.getCurrentSession() in currentSession() function of xxxDAOImpl class, use sessionFactory.openSession().
Since in your first call there would not be any current session in the session factory so you need to open the session.
Hope this helps you. Cheers.

My repository can't initialize automatically while using Spring Data JPA

I am trying to add spring data jpa to my spring-mvc web project after exploring a couple of tutorials. But I found my repository can't initialize automatically, I got NullPointerException in my service class. Please see my following sample code:
My repository:
public interface SubjectRepository extends JpaRepository<PSubject, String>{
public Page<PSubject> findByType(String title, Pageable pageable);
public Page<PSubject> findByType(String title);
public Page<PSubject> findByMacaddress(String macaddress, Pageable pageable);
public Page<PSubject> findByMacaddress(String macaddress);
public Page<PSubject> findByUri(String uri);
}
My controller:
#Controller
#RequestMapping("/subject")
public class VPSubjectController
{
....
#RequestMapping("/{id}.htm")
public ModelAndView detail(#PathVariable String id)
{
ModelAndView mav = new ModelAndView("subject/detail");
PSubject subject = subjectService.get(id);
....
}
}
My Service:
#Service("subjectService")
public class SubjectServiceImpl extends VPService implements SubjectService
{
#Autowired
private SubjectRepository subjectRepository;
......
#Override
#Transactional(propagation=Propagation.REQUIRED, readOnly=true)
public PSubject get(String subject) {
PSubject subObj = subjectRepository.findOne(subject);
return subObj;
}
.....
My configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
....
<jpa:repositories base-package="com.mypacke.repository" repository-impl-postfix="Impl" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>
....
I found in this line subjectRepository.findOne(subject) ,subjectRepository is null,
My question is similar this post
#Autowired annotation is activated by the statement:
<context:component-scan base-package="base.package"/>
If u do that, it would be initialized

Resources