SpringMVC+AspectJ not called - spring

Hi I read all previous threads on my issue and i applied all suggestions, but i haven't found a solution.
In my springMVC+AspectJ config, controller works fine but the pointcut is not performed.
Here my configs and code:
-- /WEB-INF/web.xml ---
<web-app>
<display-name>MODULE-WEB</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
**
-- /WEB-INF/ApplicationContext.xml -----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"
>
<mvc:annotation-driven/>
<context:annotation-config/>
<context:component-scan base-package="it.max.test"/>
<!-- AOP -->
<aop:aspectj-autoproxy/>
<!-- EJB -->
<bean id="testService" class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:app/MODULE-EJB/TestService"/>
<property name="businessInterface" value="it.max.test.services.ITestService"/>
</bean>
</beans>
**
-- Monitor.java ---
package it.max.test.security;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
#Component
#Target(value={ElementType.METHOD, ElementType.TYPE})
#Retention(value=RetentionPolicy.RUNTIME)
public #interface Monitor {
}
**
-- AuthorizationInterceptor.java --
package it.max.test.security;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class AuthorizationInterceptor {
#Before(value="#within(it.max.test.security.Monitor) || #annotation(it.max.test.security.Monitor)")
public void before(JoinPoint jp){
Object[] paramValues=jp.getArgs();
String[] paramNames=((CodeSignature)jp.getStaticPart().getSignature()).getParameterNames();
for(int i=0;i<paramValues.length;i++){
System.out.println("["+paramNames[i]+"]:["+paramValues[i]+"]");
}
}
}
**
--TestController.java---
package it.max.test.controllers;
import it.max.test.security.Monitor;
import it.max.test.services.ITestService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class TestController {
#Autowired
private ITestService testService;
#Monitor
#RequestMapping("/test.view")
protected ModelAndView test(HttpServletRequest arg0,HttpServletResponse arg1) throws Exception {
ModelAndView mv=new ModelAndView();
testService.test("AAA");
mv.setViewName("test");
return mv;
}
}

Your annotated method is protected, but it should be public.
Spring manual, chapter 9.2.3 says:
Due to the proxy-based nature of Spring’s AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn’t applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!
If you want to match protected or private methods, use AspectJ via LTW.

Related

Why isn't #Autowired working in my Spring MVC #Controller?

I have a Spring MVC project going.
I have a WebController that has an #Autowired service.
When I run the web app on the server, the WebController is created but it doesn't autowire the service.
Been really banging my head against a wall trying to figure this out ... Any idea what's wrong?
Here's the error I get ...
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'webController':
Unsatisfied dependency expressed through field 'myAppService';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.mycompany.myapp.controller.MyAppService'
available: expected at least 1 bean which qualifies as
autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here's my web.xml ...
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Here's my dispatcher-servlet.xml ...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.mycompany.myapp" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
I have a WebController like so ...
package com.mycompany.myapp.controller;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mycompany.myapp.model.TableRecord;
#Controller
public class WebController {
#Autowired
MyAppService myAppService;
#RequestMapping(value = "/showprojects", method = RequestMethod.GET)
public ModelAndView showProjects(Model model) {
ModelAndView mav = new ModelAndView();
try {
Set<TableRecord> recProjects = myAppService.getProjects();
model.addAttribute("projects", recProjects);
} catch (Exception x) {
x.printStackTrace();
}
mav.setViewName("projects");
return mav;
}
Here's my Service interface ...
package com.mycompany.myapp.controller;
import java.util.Set;
import org.springframework.stereotype.Component;
import com.mycompany.myapp.model.TableRecord;
#Component
public interface MyAppService {
public Set<TableRecord> getProjects() throws Exception;
}
And here's my Service implementation ...
package com.mycompany.myapp.controller;
import java.util.Set;
import org.springframework.stereotype.Component;
/* ... other import statements ... */
#Component
public class MyAppServiceImpl {
public MyAppServiceImpl() throws Exception {
/* ... some initialization of member variables
and db connection ... */
}
public Set<TableRecord> getProjects() throws Exception {
/* ... implementation that returns a Set... */
}
}
You didnt implement the interface in your service class- Change it as below-
public class MyAppServiceImpl implements MyAppService {
}
It should better to use #Service annoation for service class instead of #Component
Your MyAppServiceImpl class does not implement the MyAppService interface.

Spring Inject PersistenceContext

Trying to implement a DDD architecture with aspect oriented tests that access a database and check if user exists, using AspectJ LTW...
Currently I am faces with two issues, I don't know if this class is being injected in a Spring context. I have tried to add the
//#RunWith(SpringJUnit4ClassRunner.class)
//#ContextConfiguration(locations = {"classpath*:EntityTest-context.xml"})
With no sucess. Here is the test that I am trying to run. If you notice I am creating the EntityManager on the #Before I don't know if this is a proper usage, because when I try to find the object that is created I get returned null.
package ienterprise.common.aspects;
import ienterprise.common.model.CompanyPosition;
import ienterprise.common.model.InternalUser;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import static org.junit.Assert.assertEquals;
import org.springframework.test.context.ContextConfiguration;
//#RunWith(SpringJUnit4ClassRunner.class)
//#ContextConfiguration(locations = {"classpath*:EntityTest-context.xml"})
public class EntityTest {
private static final Logger logger = LoggerFactory.getLogger(EntityTest.class);
// #PersistenceContext(unitName="mysql") // FIXME inject this in unit tests
private static EntityManager manager;
#Before
public void setUp(){
EntityManagerFactory mngFactory = Persistence.createEntityManagerFactory("mysql");
manager = mngFactory.createEntityManager();
}
#Test
public void createUser(){
InternalUser someGuy = new InternalUser();
someGuy.setName("Adam");
someGuy.setUser("Engineer");
someGuy.create();
logger.debug("created user: {}", someGuy);
//FIXME: Can't find the user in the database.
InternalUser foundUser = manager.find(InternalUser.class, 1L);
logger.debug("fetched user: {}",foundUser);
assertEquals( someGuy, foundUser);
}
}
Our 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"
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">
<context:load-time-weaver/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property>
</bean>
</beans>
How can I remove the #Before and inject a PersistenceContext?
How can I make sure that my class has a Spring Context?
This is all new stuff for me, and I would appreciate some links to github repositories if there are any with this kind of Spring+Hibernate+AspectJ+JUnit setup.
Let me know if something is not clear or additional detail is necessary.

#Cacheable "annotation type not applicable to this kind of declaration"

I'm learning Spring and Data JPA. I have a problem with Ehcache. I want to cache the return value of one of my methods that returns some records from database. This is an exercise with Ehcache instance pre-configured (I assume). The problem is that I cannot use the annotation #Cacheable to mark my method as the method that its return value should be cached. I get an incompatible type compile error (required: boolean, found: String). Here is one of the classes in my service layer that I think I should put #Cacheable here (am I right?):
package wad.datatables.service;
import javax.persistence.Cacheable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import wad.datatables.domain.Book;
import wad.datatables.repository.BookRepository;
import wad.datatables.view.DataTablesResponse;
#Service
public class JpaDataTablesBookService implements DataTablesBookService {
#Autowired
private BookRepository bookRepository;
#Override
#Transactional(readOnly = true)
#Cacheable("books")
public DataTablesResponse getBooks(String queryString) {
Pageable pageable = new PageRequest(0, 10, Sort.Direction.ASC, "title");
Page<Book> page = bookRepository.findByTitleContaining(queryString, pageable);
DataTablesResponse response = new DataTablesResponse();
response.setTotalRecords(page.getTotalElements());
response.setTotalDisplayRecords(page.getNumberOfElements());
response.setData(page.getContent());
return response;
}
}
And my repository layer (only one class):
package wad.datatables.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import wad.datatables.domain.Book;
public interface BookRepository extends JpaRepository<Book, Long> {
Page<Book> findByTitleContaining(String title, Pageable pageable);
}
And here are my config files:
cache.xml (located in WEB-INF/spring/):
<?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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
</beans>
And ehcache.xml (located in src/main/resources):
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<cache name="books" maxEntriesLocalHeap="1000" eternal="true" memoryStoreEvictionPolicy="LRU"/>
</ehcache>
The error is because you are using wrong Cacheable annotation. Instead of javax.persistence.Cacheable use org.springframework.cache.annotation.Cacheable.

#TestExecutionListeners is not present for class

I will try to test one of methods in my endpoint (spring 3.1, junit 4.11) Here are my codes:
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns: p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schem...ng-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schem...-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schem...ontext-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schem...ring-cache.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="app.controller, app.samples" />
<context:annotation-config/>
<annotation-driven />
</beans>
and test class:
package app.tests;
import app.samples.TableEndpoint;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autow ired;
import org.springframework.test.context.ContextConfigurat ion;
import org.springframework.test.context.junit4.SpringJUni t4ClassRunner;
#ContextConfiguration(locations = {"classpath:/WEB-INF/applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class TableTest {
public TableTest() {
}
#Autowired
TableEndpoint tableEndpoint;
#Test
public void testTableEndpoint(){
String result = tableEndpoint.getDane().get(0);
String expResult = "Learn python in 7 days";
if(!result.equals(expResult)){
fail("not equals");
}
assertTrue(result.equals(expResult));
}
}
If I run test I have got :
org.springframework.test.context.TestContextManage r retrieveTestExecutionListeners<br>
INFO: #TestExecutionListeners is not present for class [class app.tests.TableTest]: using defaults.
I searched about it but didn't find some informations. Thanks for help!
You miss the TestExecutionListeners. Add this annotation to your class
#TestExecutionListeners( { DependencyInjectionTestExecutionListener.class })
#ContextConfiguration(locations = {"classpath:/WEB-INF/applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class TableTest {
...
}

Spring AnnotationHandlerMapping not working

I'm new to spring controllers using annotated controllers.
Here is my configuration
Bean definition
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
Controller
package learn.web.controller.annotation;
import javax.servlet.http.HttpServletRequest;
import learn.web.controller.BaseController;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class FirstController extends BaseController {
#RequestMapping("/annotation/first.ftl")
public ModelAndView first(HttpServletRequest request) {
if(messageSource instanceof ReloadableResourceBundleMessageSource){
ReloadableResourceBundleMessageSource m = (ReloadableResourceBundleMessageSource) messageSource;
m.clearCache();
}
messageSource.getMessage("learn.message.first", new Object[] {},
localResolver.resolveLocale(request));
return new ModelAndView("/annotation/first");
}
}
When tried to access the given URL Spring is throwing a warning org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/Learn/annotation/first.ftl] in DispatcherServlet with name 'springapp'
I think what you are missing is the component scan
<context:component-scan base-package="learn.web.controller" />
Add this to your configuration and try.
This will load all annotated components from the specified package
Your configuration may look like this
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="learn.web.controller" />
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
</beans>

Resources