This question already has an answer here:
Combining Spring project and Jersey
(1 answer)
Closed 6 years ago.
How do I autowire my spring beans in a jersey resource?
I'm trying to cobble together a jersey app which uses spring to initialise the fields in the jax-rs resources. From googling, it seems possible but they are always null. My beans get created but not injected.
My REST resource
#Path ("/clips")
#Component
public class ClipStreamService {
#Autowired
private ClipHandler clipHandler;
#GET
public Response defaultGet() {
Clip clip = clipHandler.getDefault(); <-- ***** throws an NPE *****
The spring WebInitilizer
public class SpringWebInitialiser implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class);
rootContext.setServletContext(container);
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
And the bean config (note I've also tried adding the bean to RootConfig)
#Configuration
#ComponentScan ({ ... })
public class WebConfig {
#Bean
public ClipHandler clipHandler() {
return new ClipHandler();
}
}
You can manually invoke autowiring in your jersey resource like below:
#Context
private ServletContext servletContext;
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletContext);
}
Related
I try to follow answers to this question, but still cannot make it work.
I have following Java config classes:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(WebAppConfiguration.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
And for security:
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(WebSecurityConfiguration.class);
}
}
The problem is I get exception like that on startup:
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
Without SecurityWebApplicationInitializer class it starts up and works fine except of the fact that Spring Security doesn't work.
I understand that the problem is that SecurityWebApplicationInitializer injects it's own context. But then what is the right way to make the Spring Security work for my case?
Thank you.
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;
}
}
I'm trying to build a Restful webapp using Spring MVC 4.
But I'm got this error "Ambiguous handler methods mapped for HTTP".
In my controller I have this endpoints:
GET /people/
GET /people/{id}
POST /people/
DELETE /peope/{id}
PUT /people/{id}
I think this error occurs because I have something wrong in my configuration.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.myapp.rest.controller" })
public class MVCConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/site/**").addResourceLocations("/WEB-INF/site/**");
}
}
And this
public class WebAppInitializer implements WebApplicationInitializer {
#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 AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.myapp.config");
return context;
}
}
Thank you all
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.
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.