Can not assign ServletContext spring 3 - java

I am trying to use servletcontext.getRealPath in my Util class to load a file resource (Not part of unit testing) but it does not work.
I tried both to use "implements ServletContextAware":
#Component
public class Utils implements ServletContextAware{
private ServletContext servletContext;
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
System.out.println("**** "+servletContext);
}
}
Which throws NPE since servletcontext is not assigned by spring.
And the #Autowired route:
#Component
public class Utils{
#Autowired
private ServletContext servletContext;
Which throws NoSuchBeanDefinitionException when tomcat is being starting:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.servlet.ServletContext] found for dependency: expected at le
ast 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I am adding the my initialization code in case I am doing something wrong which prevents Spring to inject the right bean.
public class WebAppInitializer implements WebApplicationInitializer {
private static Logger LOG = LoggerFactory.getLogger(WebAppInitializer.class);
#Override
public void onStartup(ServletContext servletContext) {
WebApplicationContext rootContext = createRootContext(servletContext);
configureSpringMvc(servletContext, rootContext);
FilterRegistration.Dynamic corsFilter = servletContext.addFilter("corsFilter", CORSFilter.class);
corsFilter.addMappingForUrlPatterns(null, false, "/*");
// configureSpringSecurity(servletContext, rootContext);
}
private WebApplicationContext createRootContext(ServletContext servletContext) {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
// rootContext.register(CoreConfig.class, SecurityConfig.class);
rootContext.register(CoreConfig.class);
rootContext.refresh();
servletContext.addListener(new ContextLoaderListener(rootContext));
servletContext.setInitParameter("defaultHtmlEscape", "true");
return rootContext;
}
CoreConfig.class:
#Configuration
public class CoreConfig {
#Bean
public CaptionFixture createCaptionFixture() {
return new CaptionFixture();
}
#Bean
public Utils createUtils () {
return new Utils();
}
}
Utils is the class with the servlet context.
I have looked at the suggested answers: here and here and it didnt work.

The issue is that you are calling refresh() without a ServletContext being registered, so none is available when the beans are initialized.
Get rid of this call
rootContext.refresh();
The ContextLoaderListener will take care of calling refresh(). The constructor javadoc explains what happens when the ApplicationContext passed as an argument isn't refreshed.

Related

Configuration class doesn't run when I add #Autowired WebService field

I have a setup Spring + Apache CXF and I'm trying to make CustomerWebServiceImpl injectable. To do this I should inject it within #Autowired WebServiceConfig. When I do this, the WebServiceConfig doesn't even run(checked via debugger). In stack trace I see the following exception:
NoSuchBeanDefinitionException: No qualifying bean of type 'com.beginnercourse.softcomputer.domains.customer.CustomerWebService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I've checked spring annotations, everything marked with #Component/#Service. Made sure that I don't initialize any of these beans with new. Tried to replace field autowiring by setters
I have seen that there could be unexpected problems, like here
My code:
CustomerWebService
#WebService
public interface CustomerWebService {
String addCustomer(CustomerDto newCustomer);
}
CustomerWebServiceImpl
#Component
#WebService(endpointInterface = "com.soft.domains.customer.CustomerWebService")
public class CustomerWebServiceImpl implements CustomerWebService {
#Autowired
private CustomerService customerService;
#Override
public String addCustomer(CustomerDto newCustomer) {
System.out.println("Hello world");
customerService.create(new CustomerEntity());
return "Hello " + newCustomer.getName();
}
}
WebServiceConfig
#Configuration
public class WebServiceConfig {
#Autowired
private CustomerWebService customerWebService;
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), customerWebService);
endpoint.publish("http://localhost:8080/services/customer");
return endpoint;
}
}
UPD: I seems like only one of my configuration classes(RootConfig) is initialized fine. Others are not initializing beans. Maybe WebApplicationInitializer.onStartup expect another configuration. Then what kind of startup should be used to run new CXFServlet() with such Configuration classes?
public class WebServiceDispatcherServletInitializer implements WebApplicationInitializer {
private static final String SERVICE_DISPATCHER_SERVLET = "service_dispatcher_servlet";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebServiceConfig.class, RootConfig.class, PersistenceConfig.class);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new CXFServlet());
dispatcher.addMapping("/services/*");
}
}

why this bean is not null

The following code works fine in spring 4, but I am wondering why the getBean(FooService.class) returns an already-loaded bean. I thought the sequence of bean loading is not guaranteed, meaning that it is possible to get a null bean. Is it because the loading target is a class not a String (ie. object) or is it because the FooService bean has a special scope, like prototype? If so, what is the difference between getBean(class) and getBean(object)
public abstract class AbstractService implements ApplicationContextAware {
protected ApplicationContext applicationContext;
protected FooService fooService;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#PostConstruct
protected void postConstruct() {
fooService = applicationContext.getBean(FooServiceImpl.class);
}
ApplicationContext::getBean method creates the bean of the specified type if it has not been created already.
For the following two bean classes:
#Component
public class Bean1 {
#Autowired
private ApplicationContext applicationContext;
public Bean1() {
System.out.println("Bean 1 constructor");
}
#PostConstruct
public void init() {
System.out.println("Bean 1 #PostConstruct started");
applicationContext.getBean(Bean2.class);
System.out.println("Bean 1 #PostConstruct completed");
}
}
#Component
public class Bean2 {
#Autowired
private ApplicationContext applicationContext;
public Bean2() {
System.out.println("Bean 2 constructor");
}
#PostConstruct
public void init() {
System.out.println("Bean 2 #PostConstruct started");
applicationContext.getBean(Bean1.class);
System.out.println("Bean 2 #PostConstruct completed");
}
}
the printed output during context initialization is:
Bean 1 constructor
Bean 1 #PostConstruct started
Bean 2 constructor
Bean 2 #PostConstruct started
Bean 2 #PostConstruct completed
Bean 1 #PostConstruct completed
As for different getBean methods, if you pass in a class, then exactly one bean of that class has to be present in the application context (otherwise Spring would not not which of multiple bean instances of that class you ask for), whereas searching by name allows you to get a specific named bean instance.
For starters, String is a full rights class, like any you can create yourself.
The reason you're getting something in fooService, is that the ApplicationContext getBean method is able to retrieve a managed bean according to the argument you're passing to it.
If it weren't possible to retrieve the bean, you could get some of these exceptions:
Throws: NoSuchBeanDefinitionException - if no bean of the given type
was found NoUniqueBeanDefinitionException - if more than one bean of
the given type was found BeansException - if the bean could not be
created

EntityManager injection in Tomcat

I'm trying to write a web application that will run on Tomcat 8 using Spring MVC 4, Hibernate and JPA.
I'm doing this annotation driven so no XML in the Spring code if I can help it.
I have several layers in the application: Controllers that are part of the Spring MVC web app; services and repositories (although these are not annotated as Spring services etc.), all are in different JAR files that are distributed in the web app's WAR.
I'd like to inject either EntityManager or EntityManagerFactory into my code (I'm using a variation of the repository pattern) but can't get it to work.
I also have a persistence.xml defined that sets up a persistence unit.
I've tried several things and nothing works.
I've added #PersistenceContext to both an EntityManager and EntityManagerFactory variable;
I've tried #PersistenceUnit in the repository code but no luck.
The last thing I tried (following this post Injecting EntityManager with a producer in tomcat) was to add a listener to the web app and use #Inject in my code. The listener is created but the 'createEntityManager' method is never called (and yes, I've changed it to add the #Produces annotation)
So my listener looks like this:
#Produces
public EntityManager createEntityManager() {
System.out.println("*********** EntityManagerFactoryListener - createEntityManager: ");
if (entityManagerFactory == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return entityManagerFactory.createEntityManager();
}
And my reoository looks like this
#Inject
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
System.out.println("*********** entityManager: " + entityManager);
}
The error I get is
Error creating bean with name 'hibernateRepository': Injection of autowired dependencies failed
...
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManager] ...
Am I missing something? Can I even do this in Tomcat or do I need an EJB container?
EDIT
In answer to the question I have a WebApplictionInitializer that looks like this:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context) );
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
return context;
}
and a WebMvcConfigurerAdapter that looks like:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.pluralsight")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}

Spring MVC: How to get context param when instantiate the bean?

this is simple question,
how to get servlet context parameter when spring instantiate the bean?
my servlet context xml
<beans:bean id="ApplicationInfo" class="xx.xx.xx.ApplicationInfo"/>
In my code
public class ApplicationInfo{
ApplicationInfo()
{
//get context.xml or web.xml parameter
String xxx = .......;
}
}
my pom.xml
<org.springframework-version>3.2.11.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.9</org.aspectj-version>
<org.slf4j-version>1.5.10</org.slf4j-version>
<org.springsecurity-version>3.2.5.RELEASE</org.springsecurity-version>
<org.springjpa-version>1.1.0.RELEASE</org.springjpa-version>
<hibernate.version>4.1.6.Final</hibernate.version>
<postgresql.version>9.1-901-1.jdbc4</postgresql.version>
<tiles-version>2.2.2</tiles-version>
<jackson-json-version>2.1.0</jackson-json-version>
Note: i tried to get servlet context by using #annotation ,however it is nullpointer.
If you want to access autowired bean in constructor, you have to use constructor type injection:
#Component
public class ApplicationInfo {
private final FooService fooService;
#Autowired
public ApplicationInfo(ServletContext servletContext, FooService fooService) {
this.fooService = fooService;
// do something here
}
}
If you have to (or want to) stick to XML beans definition you've got to make your class implement ServletContextAware interface, which makes Spring automatically set this dependency through setter. Instead of accessing it in constructor, you do it in method annotated with #PostConstruct which is fired when bean is fully initialized:
public class ApplicationInfo implements ServletContextAware {
private final FooService fooService;
private ServletContext servletContext;
public ApplicationInfo(FooService fooService) {
this.fooService = fooService;
}
#PostConstruct
public void init() {
// now you fooService and servletContext are set
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
<bean class="demo.ApplicationInfo">
<constructor-arg name="fooService" ref="fooService" />
</bean>
<bean id="fooService" class="demo.FooService"/>
Try with #Value annotation
public class ApplicationInfo {
#Value("${parameterName}")
private String parameter;
}

Spring bean wiring in different contexts

For datasource layer I use the following Spring Configuration file:
#Configuration
#ComponentScan(basePackages = {"com.savdev.springmvcexample.repository", "com.savdev.springmvcexample.config"})
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.savdev.springmvcexample.repository"})
public class InfrastructureContextConfiguration {
...
#Configuration
#Profile(value = "file_based")
#PropertySource("classpath:/db/config/file_based.properties")
public static class FileBasedConfiguration {
#Inject
private Environment environment;
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new org.apache.commons.dbcp.BasicDataSource();
dataSource.setDriverClassName(environment.getProperty("jdbc.driver"));
dataSource.setUrl(environment.getProperty("jdbc.url"));
dataSource.setUsername(environment.getProperty("jdbc.username"));
dataSource.setPassword(environment.getProperty("jdbc.password"));
return dataSource;
}
}
...
To run tests I load this configuration via #ContextConfiguration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { InfrastructureContextConfiguration.class, HsqldbEmbeddableDbStarterContextConfiguration.class })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
#Transactional()
#ActiveProfiles(profiles = {"file_based", "test_data"} )
public abstract class AbstractJpaJavaTestBase {
...
And it works fine.
The same InfrastructureContextConfiguration class is used in web module when DispatcherServlet is created:
public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerDispatcherServlet(servletContext);
}
private void registerDispatcherServlet(final ServletContext servletContext) {
WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
dispatcherServlet.setContextInitializers( new SpringMvcExampleProfilesInitializer());
ServletRegistration.Dynamic dispatcher;
dispatcher = servletContext.addServlet("dispatcher", dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
}
But now, I'm getting NullPointerException in the following line of InfrastructureContextConfiguration:
dataSource.setDriverClassName(environment.getProperty("jdbc.driver"));
The environment is not wired. What can I do to resolve it?
What I found. The similar issue already have been met:
same1, some solutions
seems the problem is not connected, but the last answer is the best solution
total:
Actually, the field that is injected with #Inject cannot be null. It must throws exception. As a result if it is null then - the annotation has not been applied at all. As a result the main reason is the absence of its implementation in classpath.
So I added the following in my web.pom. and it resolved the problem:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
As alternative options I could use:
#Resource instead of #Inject, and environment has been set.
Passed the envirionment as argument into the constructor, instead of wiring it via annotation. But the best case, IMHO, is fix jar dependecy.

Categories