I have created a CustomErrorHandler bean that extends org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver as a replacement for xml based configuration for handling custom error pages.The bean class is registered inside WebInitializer
which is a web.xml equivalent.The problem is that i am unable to view the custom error pages that i have designed when a '404' exception is occurred or any of those that i have configured to handle in the bean class.
This is the code for my CustomErrorHandler bean class and WebInitializer:
CustomErrorHandler.java:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
public class CustomHandlerExceptionResolver extends DefaultHandlerExceptionResolver {
private static final Logger logger = LoggerFactory
.getLogger(CustomHandlerExceptionResolver.class);
#Override
protected ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
try {
if (ex instanceof java.lang.Throwable) {
return new ModelAndView("redirect:/uncaughtException");
} else if (ex instanceof java.lang.Exception) {
return new ModelAndView("redirect:/uncaughtException");
} else if (response.getStatus()==404) {
return new ModelAndView("redirect:/resourceNotFound");
} else if (response.getStatus()==500) {
return new ModelAndView("redirect:/resourceNotFound");
} //end webflow
//error 500
else if (ex instanceof org.springframework.context.ApplicationContextException) {
logger.warn("applicationcontextexception");
return new ModelAndView("redirect:/resourceNotFound");
}
//end error 500
//default
return super.doResolveException(request, response, handler, ex);
}
catch (Exception handlerException) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
}
return null;
}
}
WebInitializer.java:
import java.util.EnumSet;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.SessionTrackingMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;
import com.knowesis.sift.service.util.PropertyFileReader;
public class WebInitializer implements WebApplicationInitializer {
#Autowired
PropertyFileReader propertyfilereader;
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
Set<SessionTrackingMode> modes = EnumSet.noneOf(SessionTrackingMode.class);
modes.add(SessionTrackingMode.COOKIE);
AnnotationConfigWebApplicationContext ctx=new AnnotationConfigWebApplicationContext();
// ctx.register(PropertyFileReaderConfig.class);
// ctx.register(RootContext.class);
ctx.register(SecurityConfig.class);
servletContext.addListener(new ContextLoaderListener(ctx));
servletContext.addListener(new HttpSessionEventPublisher());
//servletContext.addFilter("springExceptionFilter",ExceptionInterceptor.class);
servletContext.addFilter("springSecurityFilterChain",DelegatingFilterProxy.class);
servletContext.setSessionTrackingModes(modes);
AnnotationConfigWebApplicationContext dispatcherContext=new AnnotationConfigWebApplicationContext();
dispatcherContext.register(ServletContextInitializer.class);
/**
here i have registered the custom handler
*/
dispatcherContext.register(CustomHandlerExceptionResolver.class);
Dynamic servlet=servletContext.addServlet("appServlet",new DispatcherServlet(dispatcherContext));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
Is it that i need to use any other Handler class provided by spring or change my current configuration ?. I also might have made a silly mistake,so please forgive as i am new to spring framework.
Registering your class in the Spring context is not enough.
If you're using Spring > 3.1, you should have a confuguration class for your app somewhere. This class should be annotated with #Configuration and extends WebMvcConfigurationSupport (or add #EnableWebMvc) which has all the basic configuration for a Spring MVC webapp.
To register your custom HandlerExceptionResolver, you should overide the configureHandlerExceptionResolvers method in your config class.
#Override
public void configureHandlerExceptionResolvers(
List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new CustomHandlerExceptionResolver());
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
Related
I am trying to implement a Spring Integration class that takes a .xml file parses it and if it's valid move it to an "archived" directory and in case of invalidity move it to an error directory.
import com.nagarro.studentapi.integration.queue.StudentSender;
import com.nagarro.studentapi.util.XmlParser;
import org.aopalliance.aop.Advice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.file.FileHeaders;
import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.integration.file.filters.SimplePatternFileListFilter;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import java.io.File;
#Configuration
#EnableIntegration
public class IntegrationConfiguration {
private static final String XML = "*.xml";
private static final String STUDENT = "\\student.xml";
#Value("${student-api.xmlPath}")
private String inputPath;
#Value("${student-api.archivedDestination}")
private String successPath;
#Value("${student-api.errorDestination}")
private String errorPath;
#Bean
public MessageChannel messageChannel() {
return new DirectChannel();
}
#Bean
#InboundChannelAdapter(value = "messageChannel")
public MessageSource<File> messageProducer() {
FileReadingMessageSource messageSource = new FileReadingMessageSource();
messageSource.setDirectory(new File(inputPath));
messageSource.setFilter(new SimplePatternFileListFilter(XML));
return messageSource;
}
#Bean
#ServiceActivator(inputChannel = "messageChannel")
public MessageHandler handler() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(successPath));
handler.setFileExistsMode(FileExistsMode.REPLACE);
handler.setExpectReply(false);
return handler;
}
#Bean
public IntegrationFlow integrationFlow(XmlParser xmlParser) {
return IntegrationFlows.from(messageProducer(), spec -> spec.poller(Pollers.fixedDelay(1000)))
.enrichHeaders(h -> h.headerExpression(FileHeaders.ORIGINAL_FILE, "payload"))
.convert(String.class)
.transform((String path) -> xmlParser.parsePath(path))
.handle("xmlParser", "parsePath", e -> e.advice(errorAdvice()))
.get();
}
#Bean
public AbstractRequestHandlerAdvice errorAdvice() {
return new AbstractRequestHandlerAdvice() {
#Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
File file = message.getHeaders().get(FileHeaders.ORIGINAL_FILE, File.class);
try {
Object result = callback.execute();
file.renameTo(new File(successPath, STUDENT));
System.out.println("File renamed after success");
return result;
}
catch (Exception e) {
file.renameTo(new File(errorPath, STUDENT));
System.out.println("File renamed after failure");
throw e;
}
}
};
}
}
However whenever calback.execute() it's called I get this error and I don't quite understand why.
2022-09-06 18:20:07.971 ERROR 32152 --- [ scheduling-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor#1135e3d6]; nested exception is java.lang.IllegalArgumentException: No candidate methods found for messages., failedMessage=GenericMessage [payload=Student(firstname=John, lastname=Dose, cnp=123, birthDate=2000-12-12, address=Address(street=a, number=1, city=Craiova, country=Romania), grades=[Grade(discipline=a, date=2021-12-12, grade=10), Grade(discipline=b, date=2021-12-12, grade=9)]), headers={....
Although I have a message handler I suspect the reason for this problem is that i do not override the handle method. But i am unsure of how to do it.
You have several problem:
#InboundChannelAdapter and IntegrationFlows.from(messageProducer(). This way you create two independent polling endpoints for the same source.
#ServiceActivator - the endpoint to write has just read file from one of the sources.
There is no connection between #InboundChannelAdapter, your #ServiceActivator expectations and that flow.
You have .transform((String path) -> xmlParser.parsePath(path)) and then immediately after that handle("xmlParser", "parsePath") which looks, essentially the same, but does not make sense since you are going to call the same parsePath() twice, but for different payloads, where the second one is going to be as a result of the first parsePath() call.
Please, revise your logic carefully: right now some of your configuration is misleading and really error-prone. I believe that error you got is because your parsePath() expects a String, but not Student as we see in the payload for that handle().
Camunda normally uses UUIDs (e. g. 98631715-0b07-11ec-ab3b-68545a6e5055) as process instance IDs. In my project a process instance ID like 124 is being generated which looks suspicious to me.
This behavior can be reproduced as described below.
Step 1
Check out this repository and start the process engines
core-processes,
core-workflow and
domain-hello-world
so that all of them use the same shared database.
Step 2
Login to the Camunda UI at http://localhost:8080 and navigate to the tasklist.
Start the Starter process in tasklist.
Step 3
Go to the cockpit and navigate to Running process instances (http://localhost:8080/camunda/app/cockpit/default/#/processes).
Click on DomainProcess.
In column ID you will see a numeric (135 in the screenshot above) process instance ID, not a UUID.
Probable cause of the error
In core-processs engine I have the following Config class:
import org.camunda.bpm.engine.impl.history.HistoryLevel;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.camunda.bpm.engine.impl.history.handler.CompositeHistoryEventHandler;
import org.camunda.bpm.engine.impl.history.handler.HistoryEventHandler;
import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static org.apache.commons.lang3.ArrayUtils.addAll;
#Configuration
public class Config {
private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
#Autowired
#Qualifier("camundaBpmDataSource")
private DataSource dataSource;
#Autowired
#Qualifier("camundaTxManager")
private PlatformTransactionManager txManager;
#Autowired
private ResourcePatternResolver resourceLoader;
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setDataSource(dataSource);
config.setTransactionManager(txManager);
config.setDatabaseSchemaUpdate("true");
config.setHistory(HistoryLevel.HISTORY_LEVEL_FULL.getName());
config.setJobExecutorActivate(true);
config.setMetricsEnabled(false);
final Logger logger = LoggerFactory.getLogger("History Event Handler");
final HistoryEventHandler testHistoryEventHandler = new HistoryEventHandler() {
#Override
public void handleEvent(final HistoryEvent evt) {
LOGGER.debug("handleEvent | " + evt.getProcessInstanceId() + " | "
+ evt.toString());
}
#Override
public void handleEvents(final List<HistoryEvent> events) {
for (final HistoryEvent curEvent : events) {
handleEvent(curEvent);
}
}
};
config.setHistoryEventHandler(new CompositeHistoryEventHandler(Collections.singletonList(testHistoryEventHandler)));
try {
final Resource[] bpmnResources = resourceLoader.getResources("classpath:*.bpmn");
final Resource[] dmnResources = resourceLoader.getResources("classpath:*.dmn");
config.setDeploymentResources(addAll(bpmnResources, dmnResources));
} catch (final IOException exception) {
exception.printStackTrace();
LOGGER.error("An error occurred while trying to deploy BPMN and DMN files", exception);
}
return config;
}
}
If I remove this configuration (or comment the #Configuration line), the error disappears.
Questions
Why does Camunda generate a numeric process instance ID in this case (and not a UUID as in other cases)?
After adding the line
config.setIdGenerator(new StrongUuidGenerator());
in the configuration class
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setIdGenerator(new StrongUuidGenerator());
config.setDataSource(dataSource);
the process instance IDs became UUIDs again.
For details see Camunda documentation on ID generators.
I'm quite new to Spring and I have created a small webservice with Spring-boot, Hibernate and Swagger. Here is my HomeController:
package io.swagger.configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Home redirection to swagger api documentation
*/
#Controller
public class HomeController {
#RequestMapping(value = "/")
public String index() {
System.out.println("swagger-ui.html");
return "redirect:swagger-ui.html";
}
}
Everything is working well, excepting I don't understand why when I have an Internal Server Error I get a status 200 with this body for example:
{
"timestamp": "2017-12-12T23:52:02.306+0000",
"status": 500,
"error": "Internal Server Error",
"exception": "javax.persistence.PersistenceException",
"message": "org.hibernate.exception.ConstraintViolationException: could not execute statement",
"path": "/example/members/1031/subscriptions"
}
And there is the launcher :
package io.swagger;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#SpringBootApplication
#EnableSwagger2
#ComponentScan(basePackages = "io.swagger")
public class Swagger2SpringBoot extends SpringBootServletInitializer implements CommandLineRunner {
#Override
public void run(String... arg0) throws Exception {
if (arg0.length > 0 && arg0[0].equals("exitcode")) {
throw new ExitException();
}
}
public static void main(String[] args) throws Exception {
LogFactory.getLog(Swagger2SpringBoot.class).warn("test");
new SpringApplication(Swagger2SpringBoot.class).run(args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Swagger2SpringBoot.class);
}
class ExitException extends RuntimeException implements ExitCodeGenerator {
private static final long serialVersionUID = 1L;
#Override
public int getExitCode() {
return 10;
}
}
}
with the configuration :
package io.swagger;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
/**
* Make sure dates are serialised in
* ISO-8601 format instead as timestamps
*/
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonMessageConverter = (MappingJackson2HttpMessageConverter) converter;
ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
objectMapper.disable(
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
);
break;
}
}
}
}
Another one for Swagger:
package io.swagger.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
#Configuration
public class SwaggerDocumentationConfig {
ApiInfo apiInfo() {
return new ApiInfoBuilder().title("**** API").description("No description").license("").licenseUrl("")
.termsOfServiceUrl("www.****.com").version("1.0.0")
.contact(new Contact("", "", "****#****.com")).build();
}
#Bean
public Docket customImplementation() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("io.swagger.api")).build().apiInfo(apiInfo());
}
}
So why do I have this 200 status if I got a server error? At least I'd like to generate a status 500, 200 means everything was fine, and obviously it's not. Any idea ?
It appears I had implemented a custom error controller generating code from my swagger file, I deleted it and now everything is ok.
My current project is based on the structure of peholmst's vaadin4spring MVP:
https://github.com/peholmst/vaadin4spring/tree/master/samples/mvp-sample
Im using Vaadin 7.5.3, SpringBoot 1.2.5.RELEASE and JSR-330 1.0 (#Inject).
Now i want to create a new vaadin view login page in combination with spring security... My attempt was the following:
HttpSecurityConfigurer.java
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
[...]
void configure(Environment env, ApplicationContext appContext, HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/VAADIN/**", "/PUSH/**", "/UIDL/**", "/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
http
.formLogin()
.loginPage("/login").defaultSuccessUrl("/", true).permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login").permitAll();
}
[...]
LoginUI.java
import javax.inject.Inject;
import org.vaadin.spring.events.EventBus;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.UI;
import my.example.application.ui.presenter.Action;
import my.example.application.ui.presenter.LoginPresenter;
#SpringUI(path = "/login")
#Theme("valo")
#Title("MyLogin")
public class MyLoginUI extends UI {
private static final long serialVersionUID = -1746340376430847935L;
#Inject
LoginPresenter presenter;
#Override
protected void init(VaadinRequest vaadinRequest) {
eventBus.publish(this, Action.START);
setContent(presenter.getView());
}
}
LoginPresenter.java
import org.vaadin.spring.events.Event;
import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import org.vaadin.spring.navigator.Presenter;
import org.vaadin.spring.navigator.annotation.VaadinPresenter;
import my.example.application.ui.view.LoginView;
#VaadinPresenter(viewName = LoginView.NAME)
public class LoginPresenter extends Presenter<LoginView> {
#EventBusListenerMethod(scope = EventScope.SESSION, filter = StartupFilter.class)
public void onStartup(Event<Action> event) {
getView().setBody();
}
}
LoginView.java
import com.vaadin.spring.annotation.UIScope;
import javax.annotation.PostConstruct;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.navigator.View;
[...]
#UIScope
#SpringView(name = LoginView.NAME, ui = MyLoginUI.class)
public class LoginView extends VerticalLayout implements View {
private static final long serialVersionUID = 8034398112492147989L;
public static final String NAME = "loginView";
#PostConstruct
private void init() {
setMargin(true);
setSpacing(true);
setSizeFull();
}
public void setBody() {
addComponent(new Label("Heey, thats my login page! :)"));
}
#Override
public void enter(ViewChangeEvent event) {
}
}
So when i start the application my browser redirects to "http://localhost:8080/login" but its rendering only the vaadin loading animation:
Can someone help me?
I had the same problem and it took ages to figure out a workaround:
#Override
protected void configure(HttpSecurity http) throws Exception
{
// Authentication is not needed for the login page
// Permit access to VAADIN resources explicitly
http.authorizeRequests().antMatchers( "/vaadinServlet/**", "/login")
.permitAll();
// TODO: For some reason I need the "auth" URL parameter. W/o the VAADIN UI does not load
http.formLogin().loginPage("/login?auth");
http.logout().logoutSuccessUrl("/login");
// Any request needs to be authenticated. If a user is not authenticated => Login Page
http.authorizeRequests().anyRequest().authenticated();
http.csrf().disable();
}
Usually it should work without the ?auth in the login page URL(it can be any URL extension).
Usually it should work when using permitAll() at the loginPage() method.
Usually it should work without explicitly allowing /login.
If anyone has an explanation for this I would appreciate that. I debugged spring and looked into the responses of the browser. Probably it's something in the *.js files that VAADIN creates for its widgets.
I have programatically defined a Jetty server and added an instance of a HttpRequestHandlerServlet. I am trying to do all of this without a web.xml file. Here is a simplified version of my code:
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.context.support.HttpRequestHandlerServlet;
public class TestServer extends Server {
public TestServer() throws Exception {
super(8888);
final ServletContextHandler contextHandler = new ServletContextHandler(this, "/", ServletContextHandler.NO_SESSIONS|ServletContextHandler.NO_SECURITY);
final ServletContext context = contextHandler.getServletContext();
StaticApplicationContext applicationContext = new StaticApplicationContext();
applicationContext.registerSingleton("testServlet", TestBean.class);
applicationContext.refresh();
GenericWebApplicationContext webApplicationContext = new GenericWebApplicationContext();
webApplicationContext.setParent(applicationContext);
webApplicationContext.setServletContext(context);
webApplicationContext.refresh();
context.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webApplicationContext);
ServletConfig servletConfig = new ServletConfig() {
#Override
public String getServletName() {
return "testServlet";
}
#Override
public ServletContext getServletContext() {
return context;
}
#Override
public String getInitParameter(String name) {
return null;
}
#Override
public Enumeration<String> getInitParameterNames() {
return null;
}
};
HttpRequestHandlerServlet httpRequestHandlerServlet = new HttpRequestHandlerServlet();
httpRequestHandlerServlet.init(servletConfig);
ServletHolder servletHolder = new ServletHolder(httpRequestHandlerServlet);
contextHandler.addServlet(servletHolder, "/testBean");
start();
}
#Test
public void test() throws Exception {
TestServer testServer = new TestServer();
Request baseRequest = new Request();
HttpServletRequest request = mock(HttpServletRequestWrapper.class);
HttpServletResponse response = mock(HttpServletResponseWrapper.class);
testServer.handle("/testBean", baseRequest, request, response);
}
}
class TestBean implements HttpRequestHandler {
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getOutputStream().write("Steve".getBytes());
}
}
If you run the test, the following exception (root cause) occurs:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.springframework.web.context.support.HttpRequestHandlerServlet-406774688' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:570)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1108)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:270)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121)
at org.springframework.web.context.support.HttpRequestHandlerServlet.init(HttpRequestHandlerServlet.java:58)
at javax.servlet.GenericServlet.init(GenericServlet.java:241)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:477)
I am using Jetty 7.6.9.v20130131 (due to a dependency in my real project on Camel 2.12.1) and Spring 3.2.4.RELEASE.
Any help is greatly appreciated.
Steve Ardis
I knew that "The target bean name must match the HttpRequestHandlerServlet servlet-name as defined in web.xml" (see the JavaDoc on HttpRequestHandlerServlet), but I was only doing half of what was required when using the programmatic approach.
Adding the following code got me past this issue:
servletHolder.setName("testServlet");
Steve Ardis