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/*");
}
}
Related
I am trying to configure my Spring Boot application with annotations and to use #Autowired annotation in it. When I check whether I have my Bean loaded or not, it is loaded, but with #Autowired it says NoSuchBeanDefinitionException
As you can see further I tried to check if my Beans were actually loaded, so when I run my application, I can see my Bean's name in the console.
Also, I tried to add 'scanBasePackages = "com.log.iei.Logistica"' to my #SpringBootApplication annotation, but it changed nothing.
Also, I tried field autowiring
Here is my main class:
#SpringBootApplication(scanBasePackages = "com.log.iei.Logistica")
public class LogisticaApplication extends Application {
public static ConfigurableApplicationContext context;
#Override
public void init() throws Exception {
SpringApplicationBuilder builder = new SpringApplicationBuilder(AppConfig.class);
context = builder.run(getParameters().getRaw().toArray(new String[0]));
String[] beanNames = context.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
Here is part of VehicleService class:
#Component("vehicleService")
public class VehicleService implements IDao<VehicleEntity> {
private static VehicleService vehicleService;
GenericDao<VehicleEntity> dao;
public VehicleService(){
dao = new GenericDao<>(VehicleEntity.class);
System.out.println("==== VehicleService was created ====");
}
Here is part of #Autowired part:
#Component("cargoPage")
public class CargoPage extends TablePageTemplate {
#Autowired
public CargoPage(VehicleService vehicleService){
getAboveTableLine().getChildren().addAll(getAboveTableLineSetup());
setTable(getTable(), vehicleService.findAll(), VehicleEntity.getTableMapping());
And here is an error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.log.iei.Logistica.data.controllers.Services.VehicleService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1654)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1213)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760)
... 24 more
UPD: Maybe the problem is with VehicleService implementing Generic interface.
First, you have to set your base package to this:
#SpringBootApplication(scanBasePackages = "com.log")
You mapped everything correctly, however, the constructor used to #Autowire beans is not supposed to invoke any other logic. If you need to do something right after bean initialization use #PostConstruct.
This is how your code would look like:
#Service
public class CargoPage extends TablePageTemplate {
private VehicleService vehicleService;
#Autowired
public CargoPage(VehicleService vehicleService) {
this.vehicleService = vehicleService;
}
#PostConstruct
public void init() {
getAboveTableLine().getChildren().addAll(getAboveTableLineSetup());
setTable(getTable(), vehicleService.findAll(), VehicleEntity.getTableMapping());
}
}
You should check if your files are inside base packages.
For example, if you have:
com.log
.service
VehicleService.java
CargoPage.java
LogisticaAplication.java
So, inside your LogisticaApplication.java, you should add the base as the following:
#SpringBootApplication(scanBasePackages = "com.log")
public class LogisticaApplication extends Application {
public static ConfigurableApplicationContext context;
#Override
public void init() throws Exception {
SpringApplicationBuilder builder = new SpringApplicationBuilder(AppConfig.class);
context = builder.run(getParameters().getRaw().toArray(new String[0]));
String[] beanNames = context.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
I can't figure out why all my beans are null in the controller. I understand that this is a common question but I am not instantiating the object with new.
Controller:
#Controller
#RequestMapping("/store")
public class MyController {
#Autowired
private MyService myService;
#GetMapping("/getOptions")
private String getOptions(HttpServletRequest request)
{
myService.doSomething(request);
....
}
}
When I request http://localhost/store/getOptions I get a NullPointerException on myService.
MyService
#Service
public class MyService
{
....
}
WebConfig
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping()
{
return new BeanNameUrlHandlerMapping();
}
}
Main
#SpringBootApplication
#Configuration
#ComponentScan(basePackages = { "com.mypackage.config", "com.mypackage.service", "com.mypackage.controller"})
public class MyApplication
{
public static void main(String[] args)
{
if (AuthConfigFactory.getFactory() == null)
AuthConfigFactory.setFactory(new AuthConfigFactoryImpl());
SpringApplication.run(MyApplication.class, args);
}
}
When I start the application, I can see in the logs that the myService bean is actually being Autowired into the controller:
- Processing injected element of bean 'myController': AutowiredFieldElement for private com.mypackage.service.MyService com.mypackage.controller.MyController.myService
- Returning cached instance of singleton bean 'MyService'
- Autowiring by type from bean name 'myController' to bean named 'myService'
So I don't understand why when I try to access myService within the controller, it is null. I do not instantiate the controller anywhere with new.
Clipped Exception
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause:
java.lang.NullPointerException: null
at com.mypackage.controller.MyController.getOptions(MyController.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
....
Edit:
I've removed web.xml from my project, as it is irrelevant.
My problem was that some of the methods in my controller were annotated as #Transactional. I did not provide enough information in my original post for anyone to figure that out. I found the answer here: Why we shouldn't make a Spring MVC controller #Transactional?
Spring java configuration:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
#Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping(){
return new BeanNameUrlHandlerMapping();
}
}
Service class:
#Service("myService")
public class MyServiceImpl implements MyService{
#Override
public String getMessageinfo() {
// TODO Auto-generated method stub
return "Hello World!!";
}
}
Service interface:
public interface MyService {
public String getMessageinfo();
}
Controller class:
#RestController
#RequestMapping("/hello")
public class MyController {
#Autowired
private MyService myService;
#GetMapping("/getMessage")
//#ResponseBody
private String getMessage(HttpServletRequest req){
System.out.println("inside controller : - "+myService.getMessageinfo());
return myService.getMessageinfo();
}
}
SpringbootMain
#SpringBootApplication
#Configuration
#ComponentScan(basePackages={"com.example.demo.config","com.example.demo.controller","com.example.demo.service"})
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
This worked for me. without exception, but i used eclipse STS IDE and created Spring boot project.
http://localhost:8080/hello/getMessage
I am using Spring and Hibernate and I am successfully autowiring a Repository inside the contructor of a Service class. When i try to add #Transactional methods in my Service class i get an AopConfigException that it is about the generation of CGLib class.
My Configuration consists in 3 files.
An AppInitializer class that implements WebApplicationInitializer , a WebMvcConfig class that extends WebMvcConfigurerAdapter and lastly a PersistentContext class.
AppInitializer
public class AppInitializer implements WebApplicationInitializer {
private static final String CONFIG_LOCATION = "com.project.app.config";
private static final String MAPPING_URL = "/";
#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(MAPPING_URL);
}
private AnnotationConfigWebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(CONFIG_LOCATION);
return context;
}
WebMvcConfig
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "com.project.app" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Autowired
private Environment env;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("hello");
}
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
}
PersistentContext
#Component
#EnableJpaRepositories("com.project.app.services.repositories")
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class PersistenceContext {
#Autowired
private Environment env;
#Bean
#Primary
public DataSource dataSource() throws ClassNotFoundException {
DataSource ds = new DataSource();
ds.setUrl(env.getProperty(SystemSettings.DS_URL));
ds.setUsername(env.getProperty(SystemSettings.DS_USERNAME));
ds.setPassword(env.getProperty(SystemSettings.DS_PASSWORD));
ds.setDriverClassName(env.getProperty(SystemSettings.DS_DRIVER));
return ds;
}
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("com.project.app.services.entities");
// .. Set Properties..
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
The Repository INTERFACE extends CrudRepository
StopRepository
#Repository
#RepositoryRestResource(collectionResourceRel = "stop", path = "stop")
public interface StopRepository extends CrudRepository<StopJPA, Long> {
#Override
StopJPA save(StopJPA persisted);
}
The Entity class.
StopJPA
#Entity
#Table(name = "stop")
public class StopJPA implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "stop_description")
private String stopDescription;
#Column(name = "id_stop", nullable = false)
private String idStop;
public StopJPA() {
}
public StopJPA(String stopDescription, String idStop) {
this.stopDescription = stopDescription;
this.idStop = idStop;
}
// .. Getters & Setters ..
}
And the Service class implementation:
StopService
#Service
final class RepoStopService {
private StopRepository stopRepository;
#Autowired
RepoStopService(StopRepository stopRepository) {
this.stopRepository = stopRepository;
}
#Transactional
public StopDTO create(StopDTO newEntry) {
StopJPA created = new StopJPA(newEntry.getStopDescription(), newEntry.getIdStop());
created = stopRepository.save(created);
return EntitiesConverter.mapEntityIntoDTO(created);
}
}
Unfortunately when i try to run it on server i get this exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'repoStopService' defined in file [C:..\RepoStopService.class]: Initialization of bean failed;
Caused by: org.springframework.aop.framework.AopConfigException:Could not generate CGLIB subclass of class [class ..RepoStopService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class ..RepoStopService
I understand that Spring uses either JDK proxy or CGLib. The default behavior if we autowire an interface (here its the repository) is to have a JDK proxy?
what need to be changed in order to make it work?
The exception message is quite clear
AopConfigException:Could not generate CGLIB subclass of class [class ..RepoStopService
First of all it is complaining about the fact that it cannot create a proxy for your service it doesn't mention your repositories at all. Your service is a class without an interface and it is also final.
The #Transactional is on a method in your service. Spring needs to create a proxy for your service to be able to start and commit the transaction at that point. As your service isn't implementing an interface it tries to create a class based proxy, however it cannot because your class is marked final.
To fix, remove the final or create an interface to be able to use JDK Dynamic proxies instead of Cglib based class proxies.
Note: Depending on the version of Spring used, it will still fail when removing the final keyword as on earlier versions it is also required to have a no-arg default constructor and you only have a single argument constructor.
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.