java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut - spring

I'm really very new to Spring AOP. In my application, I had configured HiddenHttpMethodFilter that converts method parameters into HTTP methods and enables Spring to handle other HTTP methods like DELETE, PUT etc including GET and POST.
It is some times necessary to disable this functionality especially when handling multipart requests. In order to disable it at a specific request (regarding mulripart), I was using the following code.
package resolver;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartResolver;
/**
* Disables the spring multipart resolver for specific client requests and
* therefore keeps the request intact so that controllers can process it in
* whatever way they wish. This behaviour is triggered by a particular GET
* parameter in the client request so it is configurable.
* #see MultipartResolver
*/
#Aspect
public final class MultipartResolverDisablingAspect
{
/**
* GET parameter which, if present in request, enables advice.
*/
private static final String DISABLING_HTTP_REQUEST_PARAMETER_KEY = "_multipartResolverDisable";
private static boolean disablingParameterExists(final HttpServletRequest request)
{
Assert.notNull(request);
return request.getParameter(DISABLING_HTTP_REQUEST_PARAMETER_KEY) != null;
}
/**
* If above GET parameter exists in request then prompt the spring multipart
* resolver to always tell spring that request is not of type multipart.
* Spring then does not process the request any further.
* #param pjp
* #param request
* #return
* #throws Throwable
*/
#Around("isMultipartOperation() && args(request)")
public Object disableIsMultipartOperation(final ProceedingJoinPoint pjp, final HttpServletRequest request) throws Throwable
{
Assert.notNull(pjp);
Assert.notNull(request);
if (disablingParameterExists(request))
{
return Boolean.FALSE;
}
return pjp.proceed();
}
/**
* Applies to any implementation of {#linkplain MultipartResolver}
*/
#SuppressWarnings("unused")
#Pointcut("execution(public boolean " + "org.springframework.web.multipart.MultipartResolver." + "isMultipart(javax.servlet.http.HttpServletRequest))")
private void isMultipartOperation() {}
}
and in the application-context.xml file, the following xml is required.
<aop:aspectj-autoproxy proxy-target-class="false" />
<bean class="resolver.MultipartResolverDisablingAspect" /> <!--Registers the above bean (class)-->
This code was taken from this article under the section - MULTIPART RESOLVER DISABLING ASPECT.
It is meant to disable multipart processing by HiddenHttpMethodFilter when a GET parameter multipartResolverDisable=1 is used as a query string as specified by the code above so that one can use commons fileupload as usual (when multipartResolverDisable=1 is supplied as a query string)
The actual question is still not in the picture. This approach was earlier working correctly in the following environment (with NetBeans 6.9.1).
Spring 3.2.0
Apache Tomcat 6.0.26.6 with the Servlet API 2.5.
Recently I have upgraded NetBeans 7.2.1 with Apache Tomcat 7.0.35 which has the Servlet API 3.0. The Spring version is the same as it was before - Spring 3.2.0.
With this updates, the approach as described above caused the following exception.
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'org.springframework.transaction.config.internalTransactionAdvisor':
Cannot resolve reference to bean
'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0'
while setting bean property 'transactionAttributeSource'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name
'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0':
Initialization of bean failed; nested exception is
**java.lang.IllegalArgumentException: error at ::0 can't find referenced
pointcut isMultipartOperation**
Where the isMultipartOperation() is the last method in the above class.
There might be a small change to the code but I know a very little about AOP and cannot figure out the cause of this exception in this nice-looking code.
What is the cause of this exception? Dose it have to do something with the Servlet API?

I think you should change your around advice to
#Around("isMultipartOperation(..) && args(request)")
your pointcut annotation to
#Pointcut("execution(* org.springframework.web.multipart.MultipartResolver.isMultipart(..)) && args(request)")
and the pointcut annotated method to
private void isMultipartOperation(HttpServletRequest request) {}
From memory, I had this issue where I was trying to wrap a pointcut with some advice, and the advice had a different number of arguments to the pointcut. In your code you appear to be using #Around to target a pointcut with args(request), but your pointcut method has no such parameter.

Related

Spring retry - can #Recover be in standalone class?

I have a Spring Integration app with multiple endpoint that process the same data in different ways.
They all have identical '#Recover' methods which has become boilerplate and seems fragile.
Can you you centralize the #Recover method (e.g. in a standalone class) and/or can you specify how to find this #Recover annotated method?
It's not clear why would one use a #Retryable in Spring Integration when there is that RequestHandlerRetryAdvice: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain...
Anyway see this option on the #Retryable:
/**
* Retry interceptor bean name to be applied for retryable method. Is mutually
* exclusive with other attributes.
* #return the retry interceptor bean name
*/
String interceptor() default "";
So, instead of #Recover method you provide your own:
#Bean
public MethodInterceptor retryInterceptor() {
return RetryInterceptorBuilder.stateless()
.maxAttempts(...)
.recoverer(...)
.build();
}
...
#Retryable(interceptor = "retryInterceptor")
public void service() {

No further requests expected while MockRestServiceServer was set to ExpectedCount.manyTimes()

I have following test class for my spring-integration application that passes sucessfully being launched alone
#SpringBootTest(classes = {BackupTestDefinition.class})
#ActiveProfiles({"test", "dev"})
#RunWith(SpringRunner.class)
public class BackupServiceTest {
#Value(value = "${ne.endpoint}")
private String ne;
#Autowired
private RestTemplate restTemplate;
private MockRestServiceServer mockServer;
#Before
public void setup() {
mockServer = MockRestServiceServer.bindTo(restTemplate).build(new UnorderedRequestExpectationManager());
mockServer.expect(ExpectedCount.manyTimes(), requestTo(UriComponentsBuilder.fromHttpUrl(ne).build().toUri())).andExpect(method(HttpMethod.POST)).andRespond(withSuccess());
}
#Test
public void testNotificationProcessing() throws IOException, InterruptedException, InitializationException, ExecutionException {
//some testing code
}
}
But I have another test that has other settings (ExpectedCount.times(1)) for the same endpoint and has different TestDefinition. So there are couple of contexts cached in this test suite. And when I launch them together I receive following exception
at org.springframework.test.web.client.AbstractRequestExpectationManager.createUnexpectedRequestError(AbstractRequestExpectationManager.java:141)
at org.springframework.test.web.client.UnorderedRequestExpectationManager.validateRequestInternal(UnorderedRequestExpectationManager.java:49)
at org.springframework.test.web.client.AbstractRequestExpectationManager.validateRequest(AbstractRequestExpectationManager.java:76)
at org.springframework.test.web.client.MockRestServiceServer$MockClientHttpRequestFactory$1.executeInternal(MockRestServiceServer.java:289)
at org.springframework.mock.http.client.MockClientHttpRequest.execute(MockClientHttpRequest.java:94)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:659)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:538)
Caused by: java.lang.AssertionError: No further requests expected: HTTP POST
After hours of debugging I found out that settings were successfully applied, but looks like restTemplate was called from another context where number of attempts was exhausted. Can you please help me to find out how this issue can be resolved.
This issue can be resolved using #DirtiesContext on the test class, alongside with the #RunWith:
* Test annotation which indicates that the
* {#link org.springframework.context.ApplicationContext ApplicationContext}
* associated with a test is <em>dirty</em> and should therefore be closed
* and removed from the context cache.
*
* <p>Use this annotation if a test has modified the context — for
* example, by modifying the state of a singleton bean, modifying the state
* of an embedded database, etc. Subsequent tests that request the same
* context will be supplied a new context.
*
* <p>{#code #DirtiesContext} may be used as a class-level and method-level
* annotation within the same class or class hierarchy. In such scenarios, the
* {#code ApplicationContext} will be marked as <em>dirty</em> before or
* after any such annotated method as well as before or after the current test
* class, depending on the configured {#link #methodMode} and {#link #classMode}.
*
And here are Docs on the matter: https://docs.spring.io/spring/docs/5.0.6.RELEASE/spring-framework-reference/testing.html#dirtiescontext

How exactly work the HandlerExceptionResolver interface in Spring? Can I show an error page when the user try to access to a not mapped resource?

I am studying how to handle custom exception in Spring on a tutorial that show me this class named ExceptionHandler that implement the HandlerExceptionResolver Spring interface:
#Component
public class ExceptionHandler implements HandlerExceptionResolver {
private static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) {
System.out.println("Spring MVC Exception Handling");
logger.error("Error: ", exception);
return new ModelAndView("error/exception","exception","ExceptionHandler message: " + exception.toString());
}
}
And then, into a controller class of the example, it throws this exception in this way:
#RequestMapping(value="/throwRunTimeException", method=RequestMethod.GET)
public void throwException() {
throw new RuntimeException();
}
So I have some doubts about how exactly do this class.
I can't understand if implementing the HandlerExceptionResolver interface I am declaring a new specific exception type or if simply specify a specific behavior that happens when a generic runtime exception is thrown.
It seems me the second situation...I think that, in the previous example, when a generic RuntimeException is thrown it return an exception.jsp page (and the related message that have to be shown into the model object).
So, if the previous assertion is true, can I use this method for the following pourpose?
I think that when a user try to open an URL that is it not mapped to any controller method a RuntimeException is thrown.
So, into the **resolveException()** method, can I extract the required URL from the HttpServletRequest request input parameter and use it to show a specific error message (that indicate that this URL not exist) into the returned view?
I don't think that is possible. When the DispatcherServlet can't find the url mapped in one of your controllers, it will throw a NoHandlerFoundException. This will then be forwarded to your servlet container like Tomcat which handles the error and shows the 404 page for example. You can change this behaviour by adding the following to your web.xml:
`
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/404error.jsp</location>
</error-page>
`
Note that it's not possible yet to configure this in JavaConfig.
For other Exceptions that are thrown you can use the HandlerExceptionResolver to return the desired view.
You could also use the #ExceptionHandler annotation on a method in your controller to catch the exceptions and handle them appropriately. This can be combined with the #ControllerAdvice annotation to enable this for every controller.

Jersey with Spring AOP

I would like my AOP advice to have a handle to the currently executing Jersey resource's HttpContext. The spring-annotations sample mentions that the user could get hold of the request and authenticate etc.,, but how does one get hold of any of the values in the Context in the advice?
Currently my resource definition looks like this:
#Singleton
#Path("/persist")
public class ContentResource {
#PUT
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Auth
public Content save(Content content){
//Do some thing with the data
}
}
And the aspect is defined so:
#Aspect
public class AuthorizeProcessor {
#Around(value="#annotation(package.Auth) and #annotation(auth)", argNames = "auth")
public Object authorize(ProceedingJoinPoint pjp, Auth auth) throws Throwable{
//How do I get the HttpContext here?
return pjp.proceed();
}
}
Granted this is most likely too late, but I did what you are doing by implementing a Servlet Filter in front of the service that does the authorization. This avoids the need for AOP entirely, and it gives you the actual ServletRequest directly without working around the system to get it.
Ironically, the question that you helped me to answer would likely help you here, if you really wanted AOP.
You can supply the Spring RequestContextFilter to the request, and then access the HttpServletRequest (as opposed to the HttpContext):
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/path/to/services/*</url-pattern>
</filter-mapping>
Access code down the filter chain:
/**
* Get the current {#link HttpServletRequest} [hopefully] being made
* containing the {#link HttpServletRequest#getAttribute(String) attribute}.
* #return Never {#code null}.
* #throws NullPointerException if the Servlet Filter for the {#link
* RequestContextHolder} is not setup
* appropriately.
* #see org.springframework.web.filter.RequestContextFilter
*/
protected HttpServletRequest getRequest()
{
// get the request from the Spring Context Holder (this is done for
// every request by a filter)
ServletRequestAttributes attributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}

Exception handler in Spring MVC

I want to create an exception handler which will intercept all controllers in my project. Is that possible to do? Looks like I have to put a handler method in each controller. Thanks for your help. I have a spring controller that sends Json response. So if an exception happens I want to send an error response which can be controlled from one place.
(I found a way to implement it in Spring 3.1, this is described in the second part of this answer)
See chapter 16.11 Handling exceptions of Spring Reference
There are some more ways than using #ExceptionHandler (see gouki's answer)
You could implement a HandlerExceptionResolver (use the servlet not the portlet package) - that is some kind of global #ExceptionHandler
If you do not have a specific logic for the exception, but only specifc view then you could use the SimpleMappingExceptionResolver, which is at least an implementation of the HandlerExceptionResolver where you can specify an Exception name pattern and the view (jsp) which is shown when the exception is thrown. For example:
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
p:defaultErrorView="uncaughtException">
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".AccessDeniedException">accessDenied</prop>
</props>
</property>
</bean>
In Spring 3.2+ one can annotate a class with #ControllerAdvice, all #ExceptionHandler methods in this class work in a global way.
In Spring 3.1 there is no #ControllerAdvice. But with a little hack one could have a similar feature.
The key is the understanding of the way #ExceptionHandler works. In Spring 3.1 there is a class ExceptionHandlerExceptionResolver. This class implements (with help of its superclasses) the interface HandlerExceptionResolver and is responsible invoking the #ExceptionHandler methods.
The HandlerExceptionResolver interface has only one Method:
ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex);`.
When the request was handled by a Spring 3.x Controller Method, then this method (represented by org.springframework.web.method.HandlerMethod) is the handler parameter.
The ExceptionHandlerExceptionResolver uses the handler (HandlerMethod) to obtain the Controller class and scan it for methods annotated with #ExceptionHandler. If one of this methods matches the exception (ex) then this methods get invoked in order to handle the exception. (else null get returned in order to signal that this exception resolver feels no responsible).
The first idea would be to implement an own HandlerExceptionResolver that behaves like ExceptionHandlerExceptionResolver, but instead of search for #ExceptionHandler in the controller class, it should search for them in one special bean. The drawback would be, that one has to (copy (or subclass ExceptionHandlerExceptionResolver) and must) configure all nice message converters, argument resolvers and return value handlers by hand (the configuration of the real one and only ExceptionHandlerExceptionResolver is done by spring automatically). So I came up with another idea:
Implement a simple HandlerExceptionResolver that "forwards" the exception to THE (already configured) ExceptionHandlerExceptionResolver, BUT with an modified handler which points to the bean that contains the global Exception handlers (I call them global, because they do the work for all controllers).
And this is the implementation: GlobalMethodHandlerExeptionResolver
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
public class GlobalMethodHandlerExeptionResolver
implements HandlerExceptionResolver, Ordered {
#Override
public int getOrder() {
return -1; //
}
private ExceptionHandlerExceptionResolver realExceptionResolver;
private List<GlobalMethodExceptionResolverContainer> containers;
#Autowired
public GlobalMethodHandlerExeptionResolver(
ExceptionHandlerExceptionResolver realExceptionResolver,
List<GlobalMethodExceptionResolverContainer> containers) {
this.realExceptionResolver = realExceptionResolver;
this.containers = containers;
}
#Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
for (GlobalMethodExceptionResolverContainer container : this.containers) {
ModelAndView result = this.realExceptionResolver.resolveException(
request,
response,
handlerMethodPointingGlobalExceptionContainerBean(container),
ex);
if (result != null)
return result;
}
// we feel not responsible
return null;
}
protected HandlerMethod handlerMethodPointingGlobalExceptionContainerBean(
GlobalMethodExceptionResolverContainer container) {
try {
return new HandlerMethod(container,
GlobalMethodExceptionResolverContainer.class.
getMethod("fakeHanderMethod"));
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
The global Handler has to implement this interface (in order to get found and to implement the fakeHanderMethod used for the handler
public interface GlobalMethodExceptionResolverContainer {
void fakeHanderMethod();
}
And example for an global Handler:
#Component
public class JsonGlobalExceptionResolver
implements GlobalMethodExceptionResolverContainer {
#Override
public void fakeHanderMethod() {
}
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public ValidationErrorDto handleMethodArgumentNotValidException(
MethodArgumentNotValidException validationException,
Locale locale) {
...
/* map validationException.getBindingResult().getFieldErrors()
* to ValidationErrorDto (custom class) */
return validationErrorDto;
}
}
BTW: You do not need to register the GlobalMethodHandlerExeptionResolver because spring automatically register all beans that implements HandlerExceptionResolver for exception resolvers. So a simple <bean class="GlobalMethodHandlerExeptionResolver"/> is enough.
Since Spring 3.2 you can use #ControllerAdvice annotation.
You can declare an #ExceptionHandler method within an #ControllerAdvice class
in which case it handles exceptions from #RequestMapping methods from all controllers.
#ControllerAdvice
public class MyGlobalExceptionHandler {
#ExceptionHandler(value=IOException.class)
public #ResponseBody String iOExceptionHandler(Exception ex){
//
//
}
// other exception handler methods
// ...
}
An abstract class where you define the exception handlers will do. And then make your controllers inherit it.

Resources