Component Scan not finding #Component's in a JAR in Tomcat webapp - spring

I just filed a bug in the Spring bugsystem ( https://jira.springsource.org/browse/SPR-8551 ), but I am still unsure if I am missing something
I tracked down a problem with <context:component-scan/> to this statement.
Given the two following classes which are in the same JAR in WEB-INF/lib of a web application (The JAR file has the directory structure):
test/TheBean.java:
package test;
#Component
public class TheBean{
}
test/BeanSearcher.java:
package test;
public class BeanSearcher{
public void init(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("test");
ctx.refresh();
TheBean b= ctx.getBean(TheBean.class);
// What is the value of b?
}
}
If I run new BeanSearcher().init() in a jUnit test case or other type of standalone application, b is getting assigned an instance of TheBean, but if I run it, say, in a JSP, ctx.getBean() is returning null.
So, am I doing something wrong or not taking something into account, is this just a bug...?
EDIT 8/8/2011: It seems to work good as I tried to simplify the problem, but still, when I try to make it work, in the initialization of OpenCms, it fails. Now I am trying to look for the differences between working versions and the one which doesn't work. (Classloader, ubication of the relevant classes in different JARs or directly in WEB-INF/classes, calls via reflection, etc.)

As I wrote in the comment, the solution is given by the answer here:
Spring Annotation-based controllers not working if it is inside jar file
When you export the jar file using the export utility in eclipse there
is a option called Add directory entries.

The obvious question is whether you have things like these in your web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/foo.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Without these, Spring won't actually load at all, let alone properly build beans…

Related

How to use an existing web.xml in my new grails 3 app?

According to the documentation here it says:
If you have a modified web.xml template then you will need to migrate this to Spring as Grails 3.x does not use a web.xml (although it is still possible to have on in src/main/webapp/WEB-INF/web.xml).
which I interpret to mean that if I'm incorporating a 3rd party proprietary library that has a web.xml, then I can put it in src/main/webapp/WEB-INF unaltered (along with everything else that they put in their tomcat webapp directory) and grails will load it. Is this interpretation correct? That's what seems to be implied by this answer.
I started a grails 3 app with the react profile (I tried the web profile too) and a webpage with calls their servlet. However, while an html file in webapp can be found, the servlet call itself is returning 404 and I can't figure out why. If I build a war file and deploy on a standalone tomcat, the servlet call works, but when I run like this:
./gradlew server:bootRun --debug
then it doesn't, and I don't see anything interesting printed to the console.
Is there some URL mapping I need to manipulate or something in application.yml?
In the web.xml, the servlet that's being called looks like this (this is a small piece of it, does it am):
<servlet>
<servlet-name>DataSourceLoader</servlet-name>
<servlet-class>com.isomorphic.servlet.DataSourceLoader</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DataSourceLoader</servlet-name>
<url-pattern>/isomorphic/DataSourceLoader</url-pattern>
</servlet-mapping>
I realize the alternative is to rewrite web.xml using Beans and put stuff in resources.groovy, but I'd prefer an approach that requires as little of my coding as possible.
[update]
I've been able to update my grails-app/conf/spring/resources.groovy with this:
import org.springframework.boot.web.servlet.ServletRegistrationBean
// Place your Spring DSL code here
beans = {
DataSourceLoader(ServletRegistrationBean) { bean ->
servlet = new com.isomorphic.servlet.DataSourceLoader()
urlMappings = ['/isomorphic/DataSourceLoader']
}
}
and it seems to be working... Nevertheless, I am still interested in ways to only use web.xml, if possible, which is my original question.
As part of an upgrade from Grails 2.x to Grails 3.3, I had been previously using web.xml to define 3rd party servlets.
The approach I took in order to make these servlets available(and load at startup) was through a custom class. So you can define a custom class, in src/java as such:
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ServletRegistrations {
#Bean
public ServletRegistrationBean fileServlet(){
ServletRegistrationBean registration = new ServletRegistrationBean(new FileServlet(), "/files/*");
// to load add startup uncomment the line below
//registration.setLoadOnStartup(1);
// define init param
registration.addInitParameter("basePath","/WEB-INF/resources");
return registration;
}
}
So although you don't define everything in one XML file, you can still define all your servlets in this one single class, so it's not a big change and I now I've gone through this once, I prefer to be able to do the definitions in code rather than xml. Hope that helps!

Jetty spring profile programmatically

I'm looking for a way to set spring profile in jetty programmatically so that the application that the war file on the server used the given profile, this is my code:
final WebAppContext context = new WebAppContext();
context.setLogUrlOnStart(true);
context.setWar("target/deployables/myapp-rest/myapp-rest.war");
context.setContextPath("/" + TEST_APP_CONTEXT);
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
I tried a couple of things but none of them seem to work... I need to pass -Dspring.profiles.active=myProfile
This is tested with Jetty 9.3 but webdefault.xml seem to also be available for lower versions (it's placement might be different though).
Go to $JETTY_HOME/etc and open webdefault.xml. Search for context-param in the file. Add this code somewhere below:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prod</param-value>
</context-param>
This will work if your web.xml (in the your-app.war file) doesn't contain this context-param.
Otherwise you could also use override-web.xml (docs) but you would need to configure it in jetty-web.xml and jetty-web.xml must be bundled inside the war... So YMMV, but I didn't want to change my war and webdefault.xml is an easier solution for me.

Spring Persistence archive and entitymanager is null when accessing from web-application

I've created a jar file through spring roo (maven project - persistence archive) unit tests are running fine, the concerned files are on the following location
jarFile/META-INF/persistence.xml
jarFile/META-INF/applicationContext.xml
jarFile/META-INF/applicationContext-jpa.xml
jarFile/META-INF/database.properties
Unit tests are running fine.
Because its a maven project I added it to local repository by executing the command "mvn install" and after that I added it as a dependency to another maven based web-application.
I am running the web application using mvn jetty:run command. the concerned files in web application are.
webApp/WEB-INF/web.xml
webApp/WEB-INF/applicationContext.xml
The Problem
* Its loading the webapp/WEB-INF/applicationContext.xml but how can I verify its loading the child jarFile/META-INF/applicationContext.xml or not? actually when i try to access the service class methods from persistence archive the entityManager is NULL.
* If i try to put contextConfigLocation directive (tried various options) within web.xml, Its not even loading the webapp/WEB-INF/applicationContext.xml.
What I want
Use the service methods (which uses entitymanager) from persistence archive from within my web application.
Thanks in advance.
Found the answer by digging around a bit.
Actually I was confused with various ways/syntax to include the context file, was trying with all sort of classpath*:xxx syntax but actually the WEB-INF is not on the class path so following have to be added to web.xml to load the main webApp/WEB-INF/applicationContext.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
Then had to add the following to the webApp/WEB-INF/applicationContext.xml
<import resource="classpath*:META-INF/spring/applicationContext*.xml" />
Now the webapplication is loading the context file from jar file as well. And things are working.

Spring:configuration xml not found in classpath

For my simple maven project this doesn't work:
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
config.xml is resided at the same class level
How,actually,add config.xml to classpath?
note: my project is a lib,if I do the same in other web project with configuration in
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config.xml</param-value>
</context-param>
that it works OK
Here I needn't web.xml, just correct classpath.
When you enter classpath*:config.xml, the classpath* is a wild card indicates that you want to load every file matching config.xml on the entire classpath, not just the single file config.xml. This may be why your solution is working otherwise.
When instantiating a new ClassPathXmlApplicationContext, try giving the full classpath as an argument: com\sergionni\myproj\config.xml.
If your config xml is in package com.anywhere.here then try this:
ApplicationContext myAppContext = new ClassPathXmlApplicationContext("com/anywhere/here/config.xml");
In case of maven project, right click on project-maven-update project, this helped me solve my issue.
Please do This code - it worked
AbstractApplicationContext context= new ClassPathXmlApplicationContext("spring-config.xml");
o/w: Delete main method class and recreate it while recreating please uncheck Inherited abstract method its worked

What is the best way to load spring config xmls?

I have to load 3 spring config xml files in myproj spring mvc app named myproj-controllers.xml, myproj-services.xml and myproj-dao.xml. I have two options to load them.
Firstly Use import resources in myproj-servlet.xml
<import resource="myproj-controllers.xml"/>
<import resource="myproj-services.xml"/>
<import resource="myproj-dao.xml"/>
or secondly in the web.xml using context param like this
<context-param>
<param-name>contextConfigLocation</param-name>
<param-values>/WEB-INF/myproj-controllers.xml</param-values>
<param-values>/WEB-INF/myproj-services.xml</param-values>
<param-values>/WEB-INF/myproj-dao.xml</param-values>
</context-param>
and adding ContextLoader listener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Which approach is recommend? And why? In my opinion I find import approach easier as we only need to make changes to myproj-servlet.xml instead of web.xml.
Spring lets you declare multiple contexts in a parent-child relation so I always went for one root applicationContext.xml containing my application beans (services, DAOs etc) and one action-servlet.xml for servlet contexts (request mappings, view resolvers etc).
I once needed action-servlet-2.xml file but still had just one root applicationContext.xml for both servlet contexts.
So (for me) it was always parent context + child context.
The only need for splitting the files into more pieces was just to reduce the size of the XMLs (which is what <import> does best).
For me, the contextConfigLocation param refers to application context files being loaded together into a single application context instance. But your files (myproj-controllers.xml, myproj-services.xml, myproj-dao.xml) seem like parts of one application context file.
For this reason I would personally go for the <import> statements and have just one value (for the root application context) in the contextConfigLocation param.
I prefer the context loader listener approach, but perhaps that's because I've never considered the import method. I'll try it out. Thanks.
I don't see any performance advantages. The WAR file has to be redeployed in either case. It's modifying one file as opposed to another. I don't see any difference. It has a bike shed feel to me, but I could be wrong.

Resources