Spring Cloud AWS - Invalid Header posting SNS notification - java

I'm trying to use org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate (from Spring Cloud AWS) to post notifications to a SNS Topic.
Every time a notification is posted a warning message is generated:
WARN [org.springframework.cloud.aws.messaging.core.TopicMessageChannel] Message header with name 'id' and type 'java.util.UUID' cannot be sent as message attribute because it is not supported by SNS.
The issue seems to be that org.springframework.messaging.MessageHeaders generates automagically an id header, of type java.util.UUID, which is not something that spring cloud knows how to handle.
Is there a way to avoid that automatic header generation (I can live without an UUID here) or avoid the warning, besides just suppressing the log?
Something similar is also affecting SQS:
Related Question:
spring-cloud-aws Spring creates message header attribute not supported by SQS
Related Bug: Warning "'java.util.UUID' cannot be sent as message attribute ..." on any request sent to SQS channel
My Controller looks something like this:
package com.stackoverflow.sample.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/whatever")
public class SampleController {
#Autowired
private NotificationMessagingTemplate template;
#RequestMapping(method = RequestMethod.GET)
public String handleGet() {
this.template.sendNotification("message", "subject");
return "yay";
}
}
}
My Spring configuration looks like this:
<?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:aws-context="http://www.springframework.org/schema/cloud/aws/context"
xmlns:aws-messaging="http://www.springframework.org/schema/cloud/aws/messaging"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/cloud/aws/context http://www.springframework.org/schema/cloud/spring-cloud-aws-context.xsd
http://www.springframework.org/schema/cloud/aws/messaging http://www.springframework.org/schema/cloud/spring-cloud-aws-messaging.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:annotation-config />
<context:component-scan base-package="com.stackoverflow.sample" />
<mvc:annotation-driven />
<aws-context:context-credentials>
<aws-context:instance-profile-credentials/>
<aws-context:simple-credentials access-key="MyKey" secret-key="mySecret" />
</aws-context:context-credentials>
<aws-messaging:notification-messaging-template id="notificationMessagingTemplate" region="us-west-2" default-destination="myTopic" />
</beans>

The problem occurs because the constructor called MessageHeaders class
MessageHeaders class
MessageHeaders(Map<String, Object> headers) { } on line 39
And to not send the id header you need to call the constructor
MessageHeaders class
MessageHeaders(Map<String, Object> headers, UUID id, Long timestamp){} on line 43
because this constructor has the condition does not create the id header automatically
to stop sending the header id you need to override the MessageHeader and NotificationMessagingTemplate classes
class MessageHeaders
public class MessageHeadersCustom extends MessageHeaders {
public MessageHeadersCustom() {
super(new HashMap<String, Object>(), ID_VALUE_NONE, null);
}
}
class NotificationMessagingTemplate
public class NotificationMessagingTemplateCustom extends NotificationMessagingTemplate {
public NotificationMessagingTemplateCustom(AmazonSNS amazonSns) {
super(amazonSns);
}
#Override
public void sendNotification(Object message, String subject) {
MessageHeaders headersCustom = new MessageHeadersCustom();
headersCustom.put(TopicMessageChannel.NOTIFICATION_SUBJECT_HEADER, subject);
this.convertAndSend(getRequiredDefaultDestination(), message, headersCustom);
}
}
And finally, your class that will make the call need to use your implementation
package com.stackoverflow.sample.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/whatever")
public class SampleController {
#Autowired
private NotificationMessagingTemplateCustom template;
#RequestMapping(method = RequestMethod.GET)
public String handleGet() {
this.template.sendNotification("message", "subject");
return "yay";
}
}
}

Related

Spring Integration - how to send POST parameters with http outbound-gateway

I'm trying to put together a really simple HTTP POST example using Spring Integration and a http outbound-gateway.
I need to be able to send a HTTP POST message with some POST parameters, as I would with curl:
$ curl -d 'fName=Fred&sName=Bloggs' http://localhost
I can get it working (without the POST parameters) if I send a simple String as the argument to the interface method, but I need to send a pojo, where each property of the pojo becomes a POST parameter.
I have the following SI config:
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<int:gateway id="requestGateway"
service-interface="RequestGateway"
default-request-channel="requestChannel"/>
<int:channel id="requestChannel"/>
<int-http:outbound-gateway request-channel="requestChannel"
url="http://localhost"
http-method="POST"
expected-response-type="java.lang.String"/>
</beans>
My RequestGateway interface looks like this:
public interface RequestGateway {
String echo(Pojo request);
}
My Pojo class looks like this:
public class Pojo {
private String fName;
private String sName;
public Pojo(String fName, String sName) {
this.fName = fName;
this.sName = sName;
}
.... getters and setters
}
And my class to kick it all off looks like this:
public class HttpClientDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/si-email-context.xml");
RequestGateway requestGateway = context.getBean("requestGateway", RequestGateway.class);
Pojo pojo = new Pojo("Fred", "Bloggs");
String reply = requestGateway.echo(pojo);
System.out.println("Replied with: " + reply);
}
}
When I run the above, I get:
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [Pojo] and content type [application/x-java-serialized-object]
I've googled a lot for this, but cannot find any examples of sending HTTP POST parameters with an outbound-gateway (I can find lots about setting HTTP Headers, but that's not what I'm trying to do here)
The only thing I did find was spring-integration: how to pass post request parameters to http-outbound but it's a slightly different use case as the OP was trying to send a JSON representation of his pojo which I am not, and the answer talks about setting headers, not POST parameters.
Any help with this would be very much appreciated;
Thanks
Nathan
Thanks to the pointers from #jra077 regarding Content-Type, this is how I solved it.
My SI config now looks like this - the important bit was adding the Content-Type header:
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<int:gateway id="requestGateway"
service-interface="RequestGateway"
default-request-channel="requestChannel">
<int:method name="sendConfirmationEmail">
<int:header name="Content-Type" value="application/x-www-form-urlencoded"/>
</int:method>
</int:gateway>
<int:channel id="requestChannel"/>
<int-http:outbound-gateway request-channel="requestChannel"
url="http://localhost"
http-method="POST"
expected-response-type="java.lang.String"/>
</beans>
Then I changed my interface to take a Map as it's argument rather than the pojo:
public interface RequestGateway {
String echo(Map<String, String> request);
}
The pojo itself remains as before; and the class that invokes the service is changed so that it creates a Map and passes it:
public class HttpClientDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/si-email-context.xml");
RequestGateway requestGateway = context.getBean("requestGateway", RequestGateway.class);
Pojo pojo = new Pojo("Fred", "Bloggs");
Map<String, String> requestMap = new HashMap<String, String>();
requestMap.put("fName", pojo.getFName());
requestMap.put("sName", pojo.getSName());
String reply = requestGateway.echo(requestMap);
System.out.println("Replied with: " + reply);
}
}
I'm sure there are several more elegant ways of transforming the pojo into a Map, but for the time being this answers my question.
To send POST parameters with a http outbound-gateway you need to set the Content-Type to application/x-www-form-urlencoded and you need to pass a Map of key/values pairs.

Spring 3 AOP and Mongo DB Integration

I was using Mongo DB with Spring Data, everything was working fine until I decided to use Spring AOP Aspects for the logging purpose. Here is my spring configuration, Person Service and LoggingAspect Code:
<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:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:annotation-config />
<context:spring-configured />
<context:component-scan base-package="com.vaap" />
<mongo:mongo host="127.0.0.1" port="27017" />
<mongo:db-factory dbname="rakeshdb" mongo-ref="mongo"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>
<bean id="personService" class="com.vaap.PersonService"></bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="loggingAspect" class="com.vaap.aop.LoggingAspect" />
</beans>
package com.vaap;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
public class PersonService implements IPersonService {
#Autowired
MongoTemplate mongoTemplate;
public static final String COLLECTION_NAME = "person";
public void addPerson(Person person) {
if (!mongoTemplate.collectionExists(Person.class)) {
mongoTemplate.createCollection(Person.class);
}
person.setId(UUID.randomUUID().toString());
// mongoTemplate.save(objectToSave, collectionName);
// DBObject dbObject = (DBObject) JSON.parse(jsonStr);
mongoTemplate.insert(person, COLLECTION_NAME);
}
public List<Person> listPerson() {
return mongoTemplate.findAll(Person.class, COLLECTION_NAME);
}
public String getPersonJSON() {
BasicQuery basicQuery = new BasicQuery("{'status':'Active'}");
return mongoTemplate.find(basicQuery, String.class, COLLECTION_NAME)
.toString();
}
public void deletePerson(Person person) {
mongoTemplate.remove(person, COLLECTION_NAME);
}
public void updatePerson(Person person) {
mongoTemplate.insert(person, COLLECTION_NAME);
}
}
package com.vaap.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
#Component
#Configurable
#Aspect
public class LoggingAspect {
static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
#AfterThrowing(pointcut = "execution(* *.*(..))", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
log.error("An exception has been thrown in "
+ joinPoint.getSignature().getName() + "()");
log.error("Cause :" + e.getCause());
}
#Around("execution(* *.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("The method " + joinPoint.getSignature().getName()
+ "() begins with " + Arrays.toString(joinPoint.getArgs()));
try {
Object result = joinPoint.proceed();
log.info("The method " + joinPoint.getSignature().getName()
+ "() ends with " + result);
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument "
+ Arrays.toString(joinPoint.getArgs()) + " in "
+ joinPoint.getSignature().getName() + "()");
throw e;
}
}
}
If I comment <aop:aspectj-autoproxy proxy-target-class="true"/> line everything works fine otherwise I am getting this error:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'mongoTemplate' defined in class path resource [SpringConfig.xml]:
Cannot resolve reference to bean 'mongoDbFactory' while setting constructor argument;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'mongoDbFactory': Initialization of bean failed;
nested exception is org.springframework.aop.framework.AopConfigException:
Could not generate CGLIB subclass of class [class org.springframework.data.mongodb.core.SimpleMongoDbFactory]:
Common causes of this problem include using a final class or a non-visible class;
nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments
I know, it may not be spring problem as this is standard CGI Lib behaviour but what alternatives do I have if I want to go with XML configuration and want to use both, spring data with mongodb and spring aop for logging.

How do I map Spring MVC controller to a uri with and without trailing slash?

I have a Spring Controller with several RequestMappings for different URIs. My servlet is "ui". The servlet's base URI only works with a trailing slash. I would like my users to not have to enter the trailing slash.
This URI works:
http://localhost/myapp/ui/
This one does not:
http://localhost/myapp/ui
It gives me a HTTP Status 404 message.
The servlet and mapping from my web.xml are:
<servlet>
<servlet-name>ui</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ui</servlet-name>
<url-pattern>/ui/*</url-pattern>
</servlet-mapping>
My Controller:
#Controller
public class UiRootController {
#RequestMapping(value={"","/"})
public ModelAndView mainPage() {
DataModel model = initModel();
model.setView("intro");
return new ModelAndView("main", "model", model);
}
#RequestMapping(value={"/other"})
public ModelAndView otherPage() {
DataModel model = initModel();
model.setView("otherPage");
return new ModelAndView("other", "model", model);
}
}
Using Springboot, my app could reply both with and without trailing slash by setting #RequestMapping's "value" option to the empty string:
#RestController
#RequestMapping("/some")
public class SomeController {
// value = "/" (default) ,
// would limit valid url to that with trailing slash.
#RequestMapping(value = "", method = RequestMethod.GET)
public Collection<Student> getAllStudents() {
String msg = "getting all Students";
out.println(msg);
return StudentService.getAllStudents();
}
}
If your web application exists in the web server's webapps directory, for example webapps/myapp/ then the root of this application context can be accessed at http://localhost:8080/myapp/ assuming the default Tomcat port. This should work with or without the trailing slash, I think by default - certainly that is the case in Jetty v8.1.5
Once you hit /myapp the Spring DispatcherServlet takes over, routing requests to the <servlet-name> as configured in your web.xml, which in your case is /ui/*.
The DispatcherServlet then routes all requests from http://localhost/myapp/ui/ to the #Controllers.
In the Controller itself you can use #RequestMapping(value = "/*") for the mainPage() method, which will result in both http://localhost/myapp/ui/ and http://localhost/myapp/ui being routed to mainPage().
Note: you should also be using Spring >= v3.0.3 due to SPR-7064
For completeness, here are the files I tested this with:
src/main/java/controllers/UIRootController.java
package controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class UiRootController {
#RequestMapping(value = "/*")
public ModelAndView mainPage() {
return new ModelAndView("index");
}
#RequestMapping(value={"/other"})
public ModelAndView otherPage() {
return new ModelAndView("other");
}
}
WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="false">
<servlet>
<servlet-name>ui</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<!-- spring automatically discovers /WEB-INF/<servlet-name>-servlet.xml -->
</servlet>
<servlet-mapping>
<servlet-name>ui</servlet-name>
<url-pattern>/ui/*</url-pattern>
</servlet-mapping>
</web-app>
WEB-INF/ui-servlet.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: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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="controllers" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:order="2"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp"/>
</beans>
And also 2 JSP files at WEB-INF/views/index.jsp and WEB-INF/views/other.jsp.
Result:
http://localhost/myapp/ -> directory listing
http://localhost/myapp/ui and http://localhost/myapp/ui/ -> index.jsp
http://localhost/myapp/ui/other and http://localhost/myapp/ui/other/ -> other.jsp
Hope this helps!
PathMatchConfigurer api allows you to configure various settings
related to URL mapping and path matching. As per the latest version of spring, trail path matching is enabled by default. For customization, check the below example.
For Java-based configuration
#Configuration
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseTrailingSlashMatch(true);
}
}
For XML-based configuration
<mvc:annotation-driven>
<mvc:path-matching trailing-slash="true"/>
</mvc:annotation-driven>
For #RequestMapping("/foo"), if trailing slash match set to false, example.com/foo/ != example.com/foo and if it's set to true (default), example.com/foo/ == example.com/foo
Cheers!
I eventually added a new RequestMapping to redirect the /ui requests to /ui/.
Also removed the empty string mapping from the mainPage's RequestMapping.
No edit required to web.xml.
Ended up with something like this in my controller:
#RequestMapping(value="/ui")
public ModelAndView redirectToMainPage() {
return new ModelAndView("redirect:/ui/");
}
#RequestMapping(value="/")
public ModelAndView mainPage() {
DataModel model = initModel();
model.setView("intro");
return new ModelAndView("main", "model", model);
}
#RequestMapping(value={"/other"})
public ModelAndView otherPage() {
DataModel model = initModel();
model.setView("otherPage");
return new ModelAndView("other", "model", model);
}
Now the URL http://myhost/myapp/ui redirects to http://myhost/myapp/ui/ and then my controller displays the introductory page.
Another solution I found is to not give the request mapping for mainPage() a value:
#RequestMapping
public ModelAndView mainPage() {
DataModel model = initModel();
model.setView("intro");
return new ModelAndView("main", "model", model);
}
try adding
#RequestMapping(method = RequestMethod.GET)
public String list() {
return "redirect:/strategy/list";
}
the result:
#RequestMapping(value = "/strategy")
public class StrategyController {
static Logger logger = LoggerFactory.getLogger(StrategyController.class);
#Autowired
private StrategyService strategyService;
#Autowired
private MessageSource messageSource;
#RequestMapping(method = RequestMethod.GET)
public String list() {
return "redirect:/strategy/list";
}
#RequestMapping(value = {"/", "/list"}, method = RequestMethod.GET)
public String listOfStrategies(Model model) {
logger.info("IN: Strategy/list-GET");
List<Strategy> strategies = strategyService.getStrategies();
model.addAttribute("strategies", strategies);
// if there was an error in /add, we do not want to overwrite
// the existing strategy object containing the errors.
if (!model.containsAttribute("strategy")) {
logger.info("Adding Strategy object to model");
Strategy strategy = new Strategy();
model.addAttribute("strategy", strategy);
}
return "strategy-list";
}
** credits:
Advanced #RequestMapping tricks – Controller root and URI Template
Not sure if this is the ideal approach, but what worked for me was to treat them as if they were two different paths and make them both accepted by each of my endpoints, such as.
#RestController
#RequestMapping("/api/mb/actor")
public class ActorController {
#GetMapping({"", "/"})
public ResponseEntity<Object> getAllActors() {
...
}
#GetMapping({"/{actorId}", "/{actorId}/"})
public ResponseEntity<Object> getActor(#PathVariable UUID actorId) {
...
}
There may be best ways to do this and to avoid this duplication, and I'd love to know that. However, what I found when I tried using configurer.setUseTrailingSlashMatch(true); is that broken paths also start becoming accepted, such as /api/mb////actor (with many slashs), and that's why I ended up going the multiple paths instead.

Spring MVC catch http errors (400.404, ....)

Good afternoon. For several days struggling over the issue. I would like to help with Spring beans (resolver) to catch all the errors in the application. Catching exceptions made almost immediately, but with capture http error is not handled.
The essence of the problem resolver can not intercept the http error.
I do not want to use the web.xml and controller, because I hope that the decision is still using the Spring context.
Implementation of catch exceptions:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<map>
...
<entry key="java.lang.Throwable" value=".error" />
</map>
</property>
<property name="defaultErrorView" value=".error"/>
</bean>
I set up mappings for the 40x errors in web.xml then handle them in a controller (which extends SimpleMappingExceptionResolver and handles the 500 ones as well)
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
#RequestMapping(value = "/404")
public String handle404(final HttpServletRequest request, final Model model) {
final String originalUri = (String)
request.getAttribute("javax.servlet.forward.request_uri");
// etc.
return "404";
}
I've got a question about the same thing here
One way is to use HandlerExceptionResolver interface.
An alternative to the HandlerExceptionResolver interface is the #ExceptionHandler annotation. You use the #ExceptionHandler method annotation within a controller to specify which method is invoked when an exception of a specific type is thrown during the execution of controller methods. For example:
package com.spring3;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class HelloWorldController {
#ExceptionHandler(Exception.class)
public ModelAndView handleMyException(Exception exception) {
ModelAndView mv = new ModelAndView("redirect:errorMessage.html?error=" + exception.getMessage());
return mv;
}
#RequestMapping(value = "/errorMessage", method = RequestMethod.GET)
public ModelAndView handleMyExceptionOnRedirect(#RequestParam("error") String error) {
ModelAndView mv = new ModelAndView("uncaughtExceptionSpring");
v.addObject("error", error);
return mv;
}
#RequestMapping("/hello")
public ModelAndView helloWorld() throws Exception {
String message = "Hello World, Spring 3.0!";
return new ModelAndView("hello", "message", message);
}
}
Spring MVC exception handling and show custom view Part1, 2, 3, 4

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

I 've designed a db application, but need to handle the exception connecting to db using spring aop, classes i 've are shown below
LoginInterface.java
LoginInterface(){
ApplicationContext context = new ClassPathXmlApplicationContext("LoginApp.xml");
Login login = (Login) context.getBean("Login");
login.loginMethod(username,password);
}
Login.java
{
loginMethod(String username, char[] pwd) throws ClassNOtFoundException, SQLException{
...
}
}
LoginProfiler.java
package dbapp;
import java.sql.SQLException;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.JoinPoint;
#Aspect
public class LoginProfiler {
#Pointcut("execution(* dbapp.Login.loginMethod(String, char[])throws java.lang.ClassNotFoundException, java.sql.SQLException)")
public void loginMethod(){}
#Around("loginMethod()")
public void handleException(final ProceedingJoinPoint pJoinPoint )throws Throwable{
try{
pJoinPoint.proceed();
}catch(Exception e) {
if((e.getCause().toString()).contains("UnknownHostException") ){
System.out.println("Unknown Host ");
}else if((e.getCause().toString()).contains("ConnectException")){
System.out.println("Connection Problem ");
}
}
}
}
LoginApp.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
default-destroy-method="destroy"
default-init-method="afterPropertiesSet"
default-autowire="byName">
<!-- Enable the #AspectJ support -->
<aop:aspectj-autoproxy />
<bean id="LoginProfiler" class="dbapp.LoginProfiler" />
<bean id="Login" class="dbapp.Login" />
</beans>
I've got the following Exception
Erg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Login' defined in class path resource [LoginApp.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut LoginMethod
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480)
at
..
Caused by: java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut LoginMethod
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:315)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:206)
at
Try this.
#Aspect
public class LoginProfiler {
#Pointcut("execution(* dbapp.Login.loginMethod(String, char[])throws java.lang.ClassNotFoundException, java.sql.SQLException)")
public void loginMethod(){}
#AfterThrowing("loginMethod()")
public void handleException(final JoinPoint joinPoint){
System.out.println("Am able to Handle");
}
}
or
#Aspect
public class LoginProfiler {
#AfterThrowing("execution(* dbapp.Login.loginMethod(String, char[])throws java.lang.ClassNotFoundException, java.sql.SQLException)")
public void handleException(final JoinPoint joinPoint){
System.out.println("Am able to Handle");
}
}
Also it would be better if you spend some time learning about spring-aop. From your question it looks like you really don't understand AOP. You are trying to cut and paste from some sample code.

Categories