In the configuration there is an error about DispatcherServletPath - spring

Error output, error occurs when the application starts and in the version spring-boot-starter-parent 2.0.5.RELEASE, in 1.5 versions it works fine. In versions 2.0.5 the distribution of the SpringBootServletInitializer file has changed;
Dependency annotations: {}
19:03:05.312 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration required a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' that could not be found.
- Bean method 'dispatcherServletRegistration' not loaded because DispatcherServlet Registration found servlet registration bean dispatcherServletRegistration
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' in your configuration.
Configuration:
#SpringBootApplication
#Import({
CityContextConfig.class,
CityPersistenceJpaConfig.class,
CityServiceConfig.class,
CityWebConfig.class
})
public class CityApp extends SpringBootServletInitializer {
#Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
final ServletRegistrationBean registration = new ServletRegistrationBean<>(dispatcherServlet(), "/api/*");
final Map<String, String> params = new HashMap<String, String>();
params.put("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
params.put("contextConfigLocation", "org.spring.sec2.spring");
params.put("dispatchOptionsRequest", "true");
registration.setInitParameters(params);
registration.setLoadOnStartup(1);
return registration;
}
//
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.initializers(new MyApplicationContextInitializer()).sources(CityApp.class);
}
public static void main(final String... args) {
new SpringApplicationBuilder(CityApp.class).initializers(new MyApplicationContextInitializer()).listeners().run(args);
}
}
The project structure is divided into two modules common and webapp

A bit old, but for the record, you can fix it quickly just adding next bean:
#Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean() {
return new DispatcherServletRegistrationBean(dispatcherServlet(), "/");
}

Servlet context path has been changed in 2.x
here are my recommendation which should work
define servlet context path in application.properties.
server.servlet.path=/ # Path of the main dispatcher servlet.
make sure you have #Configuration notation on these configuration classes CityContextConfig.class, CityPersistenceJpaConfig.class, CityServiceConfig.class, CityWebConfig.class
#SpringBootApplication
public class CityApp {
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.initializers(new MyApplicationContextInitializer()).sources(CityApp.class);
}
public static void main(final String... args) {
new SpringApplicationBuilder(CityApp.class).initializers(new MyApplicationContextInitializer()).listeners().run(args);
}
}

I am also searching for the answer. There is a migration guide from spring 1.5.x to 2.0. here Migration Guide
I think our solution is that. But I dont know how to implement their suggestion.

Related

How to set equivalent of web.xml JNDI <env-entry> in a Spring Boot project?

Referring to this SO answer, I'd like to setup the equivalent of this web.xml configuration in a JSF / JoinFaces / SpringBoot application (that doesn't have web.xml).
<env-entry>
<env-entry-name>jsf/ClientSideSecretKey</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>[AES key in Base64 format]</env-entry-value>
</env-entry>
Any pointers?
If you are using spring boot and embedded tomcat server, you can add <env-entry> programmatically with the following configuration.
#SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
#Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
#Override
protected TomcatWebServer getTomcatWebServer(org.apache.catalina.startup.Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatWebServer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
// adding <resource-ref>
ContextResource resource = new ContextResource();
resource.setName("jdbc/myJndiResource");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "org.postgresql.Driver");
resource.setProperty("url", "jdbc:postgresql://hostname:port/dbname");
resource.setProperty("username", "username");
resource.setProperty("password", "password");
context.getNamingResources()
.addResource(resource);
// adding <env-entry>
ContextEnvironment ce = new ContextEnvironment();
ce.setName("jsf/ClientSideSecretKey");
ce.setType(String.class.getName());
ce.setValue("[AES key in Base64 format]");
context.getNamingResources().addEnvironment(ce);
}
};
}
public static void main(String[] args) throws NamingException {
SpringApplication.run(DemoApplication.class, args);
}
}
Once defined the jndi naming resources they can be accessed in your application using JndiTemplate of InitialContext.
JndiTemplate jndiTemplate = new JndiTemplate();
String str = (String) jndiTemplate.lookup("java:comp/env/jsf/ClientSideSecretKey");
Hope this helps you in resolving your problem.
Essentially <env-entry> declares a web application context attribute.
You can initialize your servlet context and provide the equivalent servlet context attributes in your Spring Boot application.
For that purpose, you can register a bean that implements the ServletContextInitializer interface (or WebApplicationInitializer if your app has to be deployed in a traditional servlet container). For example:
public class JsfServletContextInitializer implements ServletContextInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setAttribute("jsf/ClientSideSecretKey", "[AES key in Base64 format]");
}
}
Do not forget to register it as a bean in your configuration.

How to query Oracle SQL with Spring Boot WAR?

Following the Spring Boot reference guides, I've set up a Hello World example. My workplace uses Ant, so I implemented build.xml based on https://www.mkyong.com/ant/ant-spring-mvc-and-war-file-example/ The resultant WAR file works correctly when deployed onto the WebLogic 12c server. Note: As per this guide, .properties files are copied to ${web.classes.dir}.
Now, I want to query the server's Oracle SQL database via JNDI. Following various parts of the Spring Boot references & guides, this is my modified code at present:
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements WebApplicationInitializer {
#Autowired
private static JdbcTemplate jdbcTemplate;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
public static void update(String query) {
jdbcTemplate.update(query);
}
}
#RestController
#RequestMapping("/query")
public class CrudController {
#RequestMapping(value="/update", method=RequestMethod.GET)
public String update(#PathVariable String tableName, /* other params */) {
// Generates query from params
Application.update(query);
return query;
}
}
I've also added an application.properties file which contains a single line in accordance with the Spring reference guide:
spring.datasource.jndi-name=jndiName
At this point, the WAR can still deploy onto the server but when I go to http://ipaddr:port/appName/query/update?params I get a NullPointerException. I've separately verified that update() correctly generates a SQL query with valid syntax, so I suspect I've gotten the database configuration wrong.
What's the correct way to connect to the JNDI database and execute a query?
Edit:
After updating my code according to Strelok's answer, I tried to run the updated WAR file on the WebLogic server, which subsequently throws the following exception:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crudController': Injection of autowired dependencies failed; ...
...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate main.java.controllers.CrudController.jdbcTemplate; ...
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionExcept‌​ion: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(req‌​uired=true)}
I tried modifying the #Autowired annotation to #Autowired(required=true) but that didn't change anything. How can I resolve this?
Your JdbcTemplate is static and is located in your application class, whereas it should belong in your controller. That's where you should use it.
Spring cannot inject static fields directly, so make sure anything injected by Spring is never static. Your code should look something like this:
Application.java
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements WebApplicationInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
CrudController.java
#RestController
#RequestMapping("/query")
public class CrudController {
#Autowired
private JdbcTemplate jdbcTemplate;
#RequestMapping(value="/update", method=RequestMethod.GET)
public String update(#PathVariable String tableName, /* other params */) {
jdbcTemplate.update(query);
return query;
}
}

How to register the Spring MVC dispatcher servlet with an embedded tomcat without spring-boot?

My question is similar to this one Embedded Tomcat Integrated With Spring. I want to run a Spring MVC Dispatcher Servlet on an embedded Tomcat. But I always end up with an exception saying that the WebApplicationObjectSupport instance does not run within a ServletContext.
My example has just the two classes:
class Application {
public static void main(String[] args) throws LifecycleException, ServletException {
try (AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext()) {
context.registerShutdownHook();
context.register(WebConfig.class);
context.refresh();
Tomcat tomcat = new Tomcat();
tomcat.setPort(9090);
File base = new File("");
System.out.println(base.getAbsolutePath());
Context rootCtx = tomcat.addWebapp("", base.getAbsolutePath());
DispatcherServlet dispatcher = new DispatcherServlet(context);
Tomcat.addServlet(rootCtx, "SpringMVC", dispatcher);
rootCtx.addServletMapping("/*", "SpringMVC");
tomcat.start();
tomcat.getServer().await();
}
}
}
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/assets/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("redirect:index.html");
}
}
How do I have to define the servlet context differently then by calling the tomcat.addWebApp(..) method? Does anybody have an example how the Spring MVC dispatcher can be used with an embedded tomcat but without boot?
You can create a ServletContextInitializer and sneak it in via #Configuration:
#Configuration
class WebAppInitConfig implements ServletContextInitializer {
#Override
void onStartup(ServletContext context) {
AnnotationConfigWebApplicationContext webAppContext = new AnnotationConfigWebApplicationContext()
webAppContext.register(RootConfig)
webAppContext.registerShutdownHook()
ServletRegistration.Dynamic dispatcher = context.addServlet("dispatcher", new DispatcherServlet(webAppContext))
dispatcher.loadOnStartup = 1
dispatcher.addMapping("/*")
// Whatever else you need
}
}

Vaadin #Push with Vaadin4Spring Security

Is anyone using Vaadin #Push with vaadin-spring-boot-starter and Vaadin4Spring Security extension?
Here is Vaadin related dependencies on our project:
compile 'com.vaadin:vaadin-client-compiled:7.5.8'
compile 'com.vaadin:vaadin-client:7.5.8'
compile 'com.vaadin:vaadin-themes:7.5.8'
compile 'com.vaadin:vaadin-server:7.5.8'
compile 'com.vaadin:vaadin-push:7.5.8'
// Official VaadinSpring Integration
compile("com.vaadin:vaadin-spring-boot-starter:1.0.0")
//Vaadin extentions - in the future more of those will go to official VaadinSpring Integration
compile("org.vaadin.spring.extensions:vaadin-spring-ext-security:0.0.6.RELEASE")
compile("org.vaadin.spring.extensions:vaadin-spring-ext-core:0.0.6.RELEASE")
compile("org.vaadin.spring.extensions:vaadin-spring-ext-boot:0.0.6.RELEASE")
compile("org.vaadin.spring.extensions:vaadin-spring-ext-test:0.0.6.RELEASE")
Here is the annotations on UI Class
#Theme("mytheme")
#Title(com.test.util.Constants.TITLE)
#EnableOAuth2Client
#SpringUI
#Push
public class MyVaadinUI extends UI {
...
}
And, Application.java ;
#EnableVaadinExtensions
#SpringBootApplication
#EnableConfigurationProperties
#EnableI18N
#EnableEventBus
#RestController
#EnableOAuth2Client
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
#Bean
public FilterRegistrationBean hiddenHttpMethodFilter() {
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(hiddenHttpMethodFilter);
return registrationBean;
}
#Bean(name = "messageSource")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages/messages");
logger.debug("Returning messageSource: " + ((messageSource != null) ? messageSource.toString() : "NULL"));
return messageSource;
}
}
As soon as we call
security.login(username.getValue(), password.getValue());
(security is org.vaadin.spring.security.VaadinSecurity;)
we get the below exception;
16:36:35.272 [http-nio-8080-exec-9] ERROR c.b.g.c.s.v.views.login.LoginBox/login Login ERROR occured during login.org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.httpService': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I appreciate any help you can provide.
You are using Websockets, which do not use servlet requests and will not activate the "request" scope automatically.
If you use #Push(transport=WEBSOCKET_XHR) it should work, as the websockets channel will then be used only for server -> client pushes and standard HTTP requests will be used for client -> server messages.

With Spring boot and integration DSL, getting error ClassNotFoundException integration.history.TrackableComponent

Trying a very basic JMS receiver using Spring Boot, Integration and DSL. I have worked on XML based on Spring Integration, but am new to Spring Boot and DSL.
This is a code sample that I have so far
#SpringBootApplication
#IntegrationComponentScan
#EnableJms
public class JmsReceiver {
static String mailboxDestination = "RETRY.QUEUE";
#Configuration
#EnableJms
#IntegrationComponentScan
#EnableIntegration
public class MessageReceiver {
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(this.connectionFactory())
.destination(mailboxDestination))
.transform((String s) -> s.toUpperCase())
.get();
}
//for sneding message
#Bean
ConnectionFactory connectionFactory() {
ActiveMQConnectionFactory acFac = new ActiveMQConnectionFactory();
acFac.setBrokerURL("tcp://crsvcdevlnx01:61616");
acFac.setUserName("admin");
acFac.setPassword("admin");
return new CachingConnectionFactory(acFac);
}
}
//Message send code
public static void main(String args[]) throws Throwable {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JmsReceiver.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
System.out.println("Sending a new mesage.");
MessageCreator messageCreator = new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("ping!");
}
};
jmsTemplate.send(mailboxDestination, messageCreator);
context.close();
}
}
And, I get this error when running with Gradle.
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFlow' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/integration/history/TrackableComponent
reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.
.
.
Caused by: java.lang.ClassNotFoundException: org.springframework.integration.history.TrackableComponent
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
My gradle dependencies:
compile "org.springframework.boot:spring-boot-starter-jersey",
"org.springframework.boot:spring-boot-starter-actuator",
"org.springframework.boot:spring-boot-configuration-processor",
"org.springframework.boot:spring-boot-starter-integration",
"org.springframework.integration:spring-integration-jms",
"org.springframework.integration:spring-integration-java-dsl:1.1.1.RELEASE",
"org.springframework.integration:spring-integration-flow:1.0.0.RELEASE",
"org.springframework.integration:spring-integration-core:4.2.2.RELEASE",
"org.springframework.integration:spring-integration-java-dsl:1.1.0.RELEASE",
"org.springframework.integration:spring-integration-flow:1.0.0.RELEASE",
"org.apache.activemq:activemq-spring:5.11.2",
UPDATE.. SOLVED: Thanks much. Changed two things:
Cleaned up gradle dependencies based on your advice. New ones looks like this:
compile "org.springframework.boot:spring-boot-starter-jersey",
"org.springframework.boot:spring-boot-starter-actuator",
"org.springframework.boot:spring-boot-configuration-processor",
"org.springframework.boot:spring-boot-starter-integration",
"org.springframework.integration:spring-integration-jms",
"org.springframework.integration:spring-integration-java-dsl:1.1.0.RELEASE",
"org.apache.activemq:activemq-spring:5.11.2"
Code was throwing constructor error about not being able to instantiate <init> in the inner class. Changed the Inner class to static. New Code:
#SpringBootApplication
#IntegrationComponentScan
#EnableJms
public class JmsReceiver {
static String lsamsErrorQueue = "Queue.LSAMS.retryMessage";
static String fatalErrorsQueue = "Queue.LSAMS.ManualCheck";
//receiver
#EnableJms
#EnableIntegration
#Configuration
public static class MessageReceiver {
#Bean
public IntegrationFlow jmsMessageDrivenFlow() {
return IntegrationFlows
.from(Jms.messageDriverChannelAdapter(this.connectionFactory())
.destination(lsamsErrorQueue))
//call LSAMS REST service with the payload received
.transform((String s) -> s.toUpperCase())
.handle(Jms.outboundGateway(this.connectionFactory())
.requestDestination(fatalErrorsQueue))
.get();
}
#Bean
ConnectionFactory connectionFactory() {
ActiveMQConnectionFactory acFac = new ActiveMQConnectionFactory();
acFac.setBrokerURL("tcp://crsvcdevlnx01:61616");
acFac.setUserName("admin");
acFac.setPassword("admin");
return new CachingConnectionFactory(acFac);
}
}
//Message send code
public static void main(String args[]) throws Throwable {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JmsReceiver.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
System.out.println("Sending a new mesage.");
MessageCreator messageCreator = new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("ping!");
}
};
jmsTemplate.send(lsamsErrorQueue, messageCreator);
context.close();
}
}
Well, that fully looks like you have a version mess in your classpath.
First of all you shouldn't mix the same artifacts manually, like you have with spring-integration-java-dsl and spring-integration-flow. BTW, do you really need the last one?.. I mean is there some reason to keep spring-integration-flow? This project is about Modular Flows.
From other side you don't need to specify spring-integration-core if you are based on the Spring Boot (spring-boot-starter-integration in your case).
And yes: the TrackableComponent has been moved to the org.springframework.integration.support.management since Spring Integration 4.2 (https://jira.spring.io/browse/INT-3799).
From here it looks like you use the older Spring Integration version somehow:
- or Spring Boot 1.2.x
- or it is really side-effect of transitive dependency from spring-integration-flow...

Resources