I work with Spring and I want to call from one Controller to another Controller.
This is my application-context file
<context:annotation-config />
<context:component-scan base-package="com.renfe.cme.mybatis,renfe.informes.resumenjornadas" />
<bean id="resumenMensualJornadasBO" class="renfe.informes.resumenjornadas.ResumenMensualJornadasBO">
</bean>
I call the first Controller from a servlet
ResumenMensualJornadasServlet resumenMensualJornadasServlet = new ResumenMensualJornadasServlet();
resumenMensualJornadasServlet.llamarController(req);
This is ResumenMensualJornadasServlet
#Controller
public class ResumenMensualJornadasServlet
{
#Autowired
private ResumenMensualJornadasBO resumenMensualJornadasBO;
public void llamarController(HttpServletRequest req) throws Exception{
this.resumenMensualJornadasBO.cargarParametrosInforme(req);
}
}
ResumenMensualJornadasBO.java is
#Component
public class ResumenMensualJornadasBO
{
#Autowired
private ResumenMensualJornadasManager resumenMensualJornadasManager;
public void cargarParametrosInforme(HttpServletRequest req) throws Exception
{
String matricula = StringUtils.recuperarParametro(req, "matricula");
String fechaDesde = StringUtils.recuperarParametro(req, "fechadesde");
String fechaHasta = StringUtils.recuperarParametro(req, "fechahasta");
resumenMensualJornadasManager.obtenerDatos(matricula, fechaDesde, fechaHasta);
}
}
I get NullPointerException when I call
this.resumenMensualJornadasBO.cargarParametrosInforme(req);
How can I fix the error in #Autowired?
EDITED
In the web.xml I have
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:com/renfe/cme/recursos/spring/applicationContext-*.xml</param-value>
<description>Spring files location</description>
</context-param>
How can I get the bean from this context?
I am using Springboot and RESTEasy to create a small webapp, in my Controller class I am doing #Autowire for my Dao class. Whenever I deploy the code, the dao reference variable always ends up with null value. I have used #Component for controller and in mail Application class I have used #SpringBootApplication and at my dao class also I have added #Repository and #Service.
Please give some suggestions where exactly i am doing wrong?
Note: Works fine if I run it as a standalone Springboot app. But this issue occurs when deploy in JBoss server.
Code format is displayed below: While debugging, at line , List<DataDto> dataList = dao.findData(); always dao is null, because of which API call fails.
#Component
#Path("/")
public class apiController {
#Autowired
private ApiDao dao;
public void setApiDao(ApiDao dao) {
this.dao = dao;
}
#GET
#Path("/getData")
#Produces(MediaType.APPLICATION_JSON)
public List<DataDto> getDetails(){
List<DataDto> dataList = dao.findData();
return logList;
}
}
Dao class code is as below:
#Repository
#Service
public class ApiDao {
private final Logger log = LoggerFactory.getLogger(ApiDao.class);
private JdbcTemplate jdbcTemplate;
#Autowired
public ApiDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<SystemEntity> findData() throws SystemException{
return entityList;
}
}
And for configuration i have used below code and in pom.xml added required dependencies:
#Component
#ApplicationPath("/rest/")
public class JaxrsApplication extends Application {
}
The Problem
JBoss provides inbuilt support for RESTEasy. So in this case the apiController is initialized twice:
Once by Spring
Once by JBoss.
The autowiring happens under the hood in the instance initialized by spring but when a call is triggered to the apiController it is handled by the instance initialized by JBoss.
Solution
Disable JBoss from initializing RESTEasy Controllers. In your spring boot application create a web.xml under src/main/webapp/WEB-INF and add the following context parameters:
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.providers</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.resources</param-name>
<param-value>false</param-value>
</context-param>
I'm using the Tuckey UrlRewriteFilter. I want to use a rewrite rule from a database, so using the <class-rule class="com.example.Foo" /> configuration, which lets you get rules at runtime. I created a class extending RewriteRule:
public class Foo extends RewriteRule {
#Autowired
private MyRepository myRepository;
public boolean init(ServletContext servletContext) {
return true;
}
#Override
public RewriteMatch matches(HttpServletRequest request, HttpServletResponse response) {
//myRepository is null
return super.matches(request, response);
}
#Override
public void destroy() {
}
}
I'd like to use a Spring Data JPA Repository inside this Foo class, but it looks the repository is null.
How can I inject it correctly?
Declare your filter in web.xml as usual, except that you will need to provide org.springframework.web.filter.DelegatingFilterProxy as the filter class name instead of your actual class name.
<filter>
<filter-name>urlRewriteFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>urlRewriteFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
Finally, in your ROOT application context, declare a bean pointing to your filter class and with the same name as the filter name provided in web.xml in the application context file loaded from web.xml:
<bean id="urlRewriteFilter" class="org.tuckey.web.filters.urlrewrite.UrlRewriteFilter"/>
Since your filter instance is now managed by Spring, you can inject any Spring managed bean into it.
I have a Servlet 3.0 web app that uses both Spring and Jersey. I currently have it set up using the SpringServlet configured as a filter in web.xml, and the resource classes annotated with both #Path and #Component. Here's the web.xml snippet:
<filter>
<filter-name>jersey-serlvet</filter-name>
<filter-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</filter-class>
<init-param>
<param-name>
com.sun.jersey.config.property.packages
</param-name>
<param-value>com.foo;com.bar</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey-serlvet</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This setup works, but I really want to get this set up with annotations only - no web.xml config. My first attempt at this was to remove the above SpringServlet configuration and create a class that extends Application. Here's a snippet of that:
#ApplicationPath("/*")
public class MyApplication extends PackagesResourceConfig {
public MyApplication() {
super("com.foo;com.bar");
HashMap<String, Object> settings = new HashMap<String, Object>(1);
settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
this.setPropertiesAndFeatures(settings);
}
}
This works in that the JAX-RS resources are registered and I can hit them at their URLs, but they throw NullPointerExceptions when they try and use their autowired properties... this makes sense because I'm guessing the resources are now being loaded by Jersey and are not Spring managed beans, therefore no autowiring.
Despite a fair bit of searching around I cannot find any way of loading the Jersey resources as Spring beans with annotations only. Is there such a way? I don't really want to have to write a bunch of code for the resources to manually fetch the Spring context and invoke the DI if I can help it.
If annotations-only isn't going to work, then I can live with the filter config in web.xml if I can specify an Application class to load instead of a list of packages to scan. If I can get rid of the package list in there and just specify an Application class instance then I'll be content.
Obviously it would be great if someone had a definitive answer for me but I'd also be grateful for any pointers or hints of where else I could look or things to try.
Thanks,
Matt
Below is part of my app, which uses Servlet 3.0, Spring, Jersey 1.8 and it has no web.xml:
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.myapp.config");
final FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", new CharacterEncodingFilter());
characterEncodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
characterEncodingFilter.setInitParameter("encoding", "UTF-8");
characterEncodingFilter.setInitParameter("forceEncoding", "true");
final FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
servletContext.addListener(new ContextLoaderListener(context));
servletContext.setInitParameter("spring.profiles.default", "production");
final SpringServlet servlet = new SpringServlet();
final ServletRegistration.Dynamic appServlet = servletContext.addServlet("appServlet", servlet);
appServlet.setInitParameter("com.sun.jersey.config.property.packages", "com.myapp.api");
appServlet.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.myapp.api.SizeLimitFilter");
appServlet.setLoadOnStartup(1);
final Set<String> mappingConflicts = appServlet.addMapping("/api/*");
if (!mappingConflicts.isEmpty()) {
throw new IllegalStateException("'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14");
}
}
}
I haven't been able to get my ideal result but I have been able to make some progress, so I'll post here in case it helps anyone else. I was able to use the Spring Servlet to specify my application class, thereby removing the package list from the web.xml.
The web.xml changes required are in the init params (the filter mapping is not shown but is still required):
<filter>
<filter-name>jersey-serlvet</filter-name>
<filter-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name> <!-- Specify application class here -->
<param-value>com.foo.MyApplication</param-value>
</init-param>
</filter>
And then in the application class I had to change the way I called the super constructor slightly:
public MyApplication() {
super("com.foo", "com.bar"); // Pass in packages as separate params
HashMap<String, Object> settings = new HashMap<String, Object>(1);
settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
this.setPropertiesAndFeatures(settings);
}
Still not exactly what I was after but at least this pulls a little more config into Java code and out of the web.xml, which is important for me as I'm trying to hide this detail.
Two options spring to mind (no pun intended).
Maybe you could extend SpringServlet with your own class and add appropriate servlet 3.0 annotations to it.
Going along with your approach of switching from the SpringServlet to an Application class, you could solve the no-autowiring problem by enabling Spring build-time or load-time bytecode weaving. That enables Spring to inject objects instantiated by anywhere instead of only objects created by Spring. See "Using AspectJ to dependency inject domain objects with Spring".
First of all, in a servlet 3.0 container you don't really need a web.xml.
But with Jersey 2.0 you can set a flag to scan the whole web app for annotated resources:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.servlet.provider.webapp</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Spring will be enabled automatically if you include this jar:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.3.1</version>
</dependency>
I used Jersey with my previously made project using SpringMVC. I based my code on the Spring's official documentation.
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) {
// Don't create the Listener that Jersey uses to create.
// There can only be one linstener
servletContext.setInitParameter("contextConfigLocation", "<NONE>");
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// Add app config packages
context.setConfigLocation("config.package");
// Add listener to the context
servletContext.addListener(new ContextLoaderListener(context));
// Replacing:
// <servlet-name>ServletName</servlet-name>
// <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
// <init-param>
// <param-name>com.sun.jersey.config.property.packages</param-name>
// <param-value>webservices.packages</param-value>
// </init-param>
// <load-on-startup>1</load-on-startup>
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
ServletRegistration.Dynamic appServlet = servletContext.addServlet("ServletName", new DispatcherServlet(dispatcherContext));
appServlet.setInitParameter("com.sun.jersey.config.property.packages", "org.sunnycake.aton.controller");
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/RootApp");
}
}
The configuration classes in config.package are:
// Specifies that there will be bean methods annotated with #Bean tag
// and will be managed by Spring
#Configuration
// Equivalent to context:component-scan base-package="..." in the xml, states
// where to find the beans controlled by Spring
#ComponentScan(basePackages = "config.package")
public class AppConfig {
/**
* Where will the project views be.
*
* #return ViewResolver como el XML
*/
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
return viewResolver;
}
}
Hibernate configuration
// Specifies that there will be bean methods annotated with #Bean tag
// and will be managed by Spring
#Configuration
// Equivalent to Spring's tx in the xml
#EnableTransactionManagement
// Equivalent to context:component-scan base-package="..." in the xml, states
// where to find the beans controlled by Spring
#ComponentScan({"config.package"})
// Here it can be stated some Spring properties with a properties file
#PropertySource(value = {"classpath:aplicacion.properties"})
public class HibernateConfig {
/**
* Inyected by Spring based on the .properties file in the
* \#PropertySource tag.
*/
#Autowired
private Environment environment;
/**
* Here it's created a Session Factory, equivalent to the Spring's config file one.
*
* #return Spring Session factory
*/
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
// Uses the datasource
sessionFactory.setDataSource(dataSource());
// Indicates where are the POJOs (DTO)
sessionFactory.setPackagesToScan(new String[]{"dto.package"});
// Se asignan las propiedades de Hibernate
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
/**
* Propiedades de la base de datos (Según environment)
*
* #return Nuevo DataSource (Configuración de la base de datos)
*/
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
/**
* Hibernate properties
*
* #return Properties set with the configuration
*/
private Properties hibernateProperties() {
Properties properties = new Properties();
// Dialect (Mysql, postgresql, ...)
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
// Show SQL query
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
/**
* Inyected by sessionFactory
*/
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
This is a full example. First of all - don't use any web.xml. Use only code below.
Rest resource:
#Path("hello")
public class HelloResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response hello() {
String output = "Hello World!";
return Response.status(200).entity(output).build();
}
}
Rest application (note "core" in package name)
#ApplicationPath("rest")
public class RestApplication extends javax.ws.rs.core.Application {
public RestApplication() {
}
#Override public Set<Class<?>> getClasses() {
return Set.of(
HelloResource.class
);
}
}
Spring web configuration.
#Configuration
#EnableWebMvc
#ComponentScan(basePackageClasses = {
})
public class WebConfig implements WebMvcConfigurer {
private static final Logger logger = LoggerFactory.getLogger(WebConfig.class);
#Autowired
private ApplicationContext applicationContext;
public WebConfig() {
}
}
Spring initializer
//This #Order is required!!!
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyWebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
var ctx = new AnnotationConfigWebApplicationContext();
//spring WebMvcConfigurer
ctx.register(WebConfig.class);
ctx.setServletContext(servletContext);
//Spring servlet
var servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
// Register Jersey 2.0 servlet
ServletRegistration.Dynamic jerseyServlet = servletContext.addServlet("jerseyServlet",
"org.glassfish.jersey.servlet.ServletContainer");
//note "javax.ws.rs.Application" doesn't have "core"
jerseyServlet.setInitParameter("javax.ws.rs.Application", RestApplication.class.getName());
jerseyServlet.addMapping("/rest/*");
jerseyServlet.setLoadOnStartup(1);
}
}
And it must work on, for example, http://127.0.0.1:8080/rest/hello
i want to use spring autowiring in servlet so here's my code:
#Configurable
public class ImageServlet extends HttpServlet {
#Autowired
private SystemPropertyDao systemPropertyDao;
#Override
public void init() throws ServletException {
String imagePath = systemPropertyDao.findByID(StaticParam.CONTENT_FOLDER);
}
while the SystemPropertyDao is annotated with #Repository
and my applicationContext.xml:
<context:component-scan base-package="com.basepackage" />
<mvc:annotation-driven />
<context:annotation-config />
<context:spring-configured/>
web.xml:
<servlet>
<servlet-name>imageServlet</servlet-name>
<servlet-class>com.xeno.basepackage.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>imageServlet</servlet-name>
<url-pattern>/myimages/*</url-pattern>
</servlet-mapping>
sometimes the autowiring works and sometimes it doesn't (the reference to the spring bean systemPropertyDao is null), can anyone please tell me if i am missing something?
I followed the solution in the following link, and it works fine:
Access Spring beans from a servlet in JBoss
public class MyServlet extends HttpServlet {
#Autowired
private MyService myService;
public void init(ServletConfig config) {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
}
Remove the #Configurable annotation from your servlet and add:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this);
at the first line of your init() method.