How to load ApplicationContext java-config in Junit - spring

I am trying to move spring xml config to java config. Right now, I am able to make everything work, except one thing, that is to run junit on my services. The problem is that my junit test couldn't detect application context. Hence, how I can load application context java-based config in Junit? Since I can run my service on a browser, I assume that my integration is correct, meaning that my test configuration is not right, but I can't find where is my be wrong.
This is my junit config:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes={Bootstrap.class, RootContextConfig.class
, WebServletContextConfig.class, PersistenceConfig.class })
#WebAppConfiguration
//#TransactionConfiguration(transactionManager="transactionManager",defaultRollback=true)
public class BaseTest { ... }
Just in case, I include my application context configuration here also.
This is my bootstrap
public class Bootstrap implements WebApplicationInitializer
{
#Override
public void onStartup(ServletContext container)
throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootContextConfig.class);
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext();
servletContext.register(WebServletContextConfig.class);
ServletRegistration.Dynamic dispatcher = container.addServlet(
"SpringDispatcher", new DispatcherServlet(servletContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
My RootContext
#Configuration
#EnableScheduling
#EnableAsync(
mode=AdviceMode.PROXY, proxyTargetClass=false,
order=Ordered.HIGHEST_PRECEDENCE
)
#ComponentScan(
basePackages={"com.core", "com.common"},
excludeFilters=#ComponentScan.Filter(Controller.class)
)
#Import({PersistenceConfig.class})
public class RootContextConfig {...}
My WebServletContext
#Configuration
#EnableWebMvc
#ComponentScan(
basePackages = { "com.web" },
useDefaultFilters = false,
includeFilters = #ComponentScan.Filter({Controller.class, ControllerAdvice.class})
)
public class WebServletContextConfig extends WebMvcConfigurerAdapter {..}
My PersistentContext
#Configuration
#EnableTransactionManagement(
mode=AdviceMode.PROXY, proxyTargetClass=false
, order=Ordered.LOWEST_PRECEDENCE)
public class PersistenceConfig {
#Bean
public DataSource customerSupportDataSource() {
//JndiDataSourceLookup lookup = new JndiDataSourceLookup();\
BasicDataSource basic = new BasicDataSource();
basic.setDriverClassName(KEY_DRIVER_CLASS);
basic.setUrl(KEY_DB_URL);
basic.setUsername(KEY_DB_USERNAME);
basic.setPassword(KEY_DB_PASSWORD);
return basic;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
Map<String, Object> properties = new Hashtable<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQLDialect");
adapter.setGenerateDdl(true);
adapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory =
new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(this.customerSupportDataSource());
factory.setPackagesToScan("com.common.model");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
factory.setJpaPropertyMap(properties);
return factory;
}
#Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject()
);
}
}

Related

NoSuchMethodException: org.springframework.boot.autoconfigure.http.HttpMessageConverters

I want to configure Spring application with Hibernate. I tried this:
Main start method:
#Configuration
#EnableWebMvc
public class WebConfig implements WebApplicationInitializer, WebMvcConfigurer {
private BasicAuthenticationInterceptor basicAuthenticationInterceptor;
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> converter instanceof MappingJackson2XmlHttpMessageConverter);
converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
converters.add(new MappingJackson2XmlHttpMessageConverter(
((XmlMapper) createObjectMapper(Jackson2ObjectMapperBuilder.xml()))
.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)));
converters.add(new MappingJackson2HttpMessageConverter(
createObjectMapper(Jackson2ObjectMapperBuilder.json())));
}
private ObjectMapper createObjectMapper(Jackson2ObjectMapperBuilder builder) {
builder.indentOutput(true);
builder.modules(new JaxbAnnotationModule());
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.defaultUseWrapper(false);
return builder.build();
}
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(ContextDatasource.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
#Autowired
public void setBasicAuthenticationInterceptor(BasicAuthenticationInterceptor basicAuthenticationInterceptor) {
this.basicAuthenticationInterceptor = basicAuthenticationInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(basicAuthenticationInterceptor);
}
}
Hibernate configuration called from rootContext.register(ContextDatasource.class);:
#SpringBootApplication
#Configuration
#EnableTransactionManagement
public class ContextDatasource {
#Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
return new FastJsonHttpMessageConverter();
}
#Bean
#Autowired
public HttpMessageConverters convertersToBeUsed(FastJsonHttpMessageConverter converter) {
return new HttpMessageConverters(converter);
}
#Bean
public LocalSessionFactoryBean getSessionFactory() throws NamingException {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setPackagesToScan(new String[] { "org.datalis.plugin.database.models" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource getDataSource() throws NamingException {
return (DataSource) new JndiTemplate().lookup("java:/global/production_gateway");
}
#Bean
public PlatformTransactionManager getHibernateTransactionManager() throws NamingException {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor getExceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MariaDBDialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
hibernateProperties.setProperty("hibernate.format_sql", "true");
return hibernateProperties;
}
}
But when I deploy the WAR file I get error:
Caused by: java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.http.HttpMessageConverters$$EnhancerBySpringCGLIB$$1d90bff9.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3302)
Full error stack:
https://pastebin.com/x30W2aws
Can you give advice where I'm wrong and how to fix the problem?
Do I need to implement the module startup with another configuration?
EDIT:
With Java 8 the code is working without above issue. With latest Java 10 I get the above exception. Do you know what configuration I need to do?
According to the Spring Boot release notes, Java 10 is supported by Spring Boot version 2.0.1 and up. Without a list of your dependencies it's impossible to know if this is the issue, but it does seem like a good place to start.
Are you running Boot v2.0.1 or higher?

How to config MessageDispatcherServlet and ServletRegistration both by using spring annotaion

I have configure MessageDispatcherServlet for soap services and ServletRegistration for web services but controller not call in case of web services.
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
// use MessageDispatcherServlet instead of standard DispatcherServlet for SOAP messages
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setContextClass(WebServiceWsConfig.class);
servlet.setApplicationContext(context);
servlet.setTransformWsdlLocations(true);
// register MessageDispatcherServlet as Web Service entry point
final ServletRegistration.Dynamic dispatcher = servletContext.addServlet("MessageDispatcherServlet",servlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/soapws/*");
dispatcher.addMapping("/");
}
}
My WebServicesConfig class is
#Configuration
#EnableWs
#EnableWebMvc
#ComponentScan(basePackages = "")
#PropertySource(value = {"classpath:config_local.properties"})
public class WebServiceConfig extends WebMvcConfigurerAdapter {
#Autowired
private Environment env;
#Bean(name = "pos")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema posSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("posPort");
wsdl11Definition.setLocationUri("/soapws");
wsdl11Definition.setTargetNamespace("http://---.---.in/soap");
wsdl11Definition.setSchema(posSchema);
return wsdl11Definition;
}
#Bean
public XsdSchema studentsSchema() {
return new SimpleXsdSchema(new ClassPathResource("pos.xsd"));
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
I solve my problem using Spring Boot configuration, This help me calling Soap services as well as Web services.
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter{
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
#Bean(name = "pos")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema posSchema)
{
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("posPort");
wsdl11Definition.setLocationUri("/soapws");
wsdl11Definition.setTargetNamespace("http://---.---.in/soap");
wsdl11Definition.setSchema(posSchema);
return wsdl11Definition;
}
#Bean
public XsdSchema studentsSchema() {
return new SimpleXsdSchema(new ClassPathResource("pos.xsd"));
}

Vaadin Spring no boot : Dependency Injection issue

I'm using Vaadin 7, Spring Data JPA 1.9.4.RELEASE, and Vaadin-Spring 1.0.0 and I have some DI problemes.
I choose not to use Spring Boot because it will automatically do too many things that I cannot "see" and I have encountered some problemes that spent me too much time to understand and find the reason, so I prefer no boot.
The probleme that I encounter is that DI works at a root UI but not for a sub-window of the root UI.
RootUI.java
#SpringUI(path = "/")
public class RootUI extends UI {
#Autowired
private EntityManagerFactory entityManagerFactory; // this one works, but I cannot get EntityManager directly
#Autowired
private ClassService classService; // this one works
#Override
protected void init(VaadinRequest request) {
...
PersonForm form = new PersonForm();
CssLayout layout = new CssLayout();
layout.addComponent(form);
Window subWindow = new Window();
subWindow.setContent(layout);
...
}
}
PersonForm.java
public class PersonForm {
#Autowired
private ClassService classService; // this doesnot work,
public PersonForm(ClassService classService) {
classService.findByName();// since the #Autowired dosenot work, I have to pass the one from rootUI.
}
init() {
classService.findByName(); // null exception
}
}
DBConfig.java
#Configuration
#EnableVaadin
#EnableJpaRepositories(basePackages = {"com.example.person.repository"})
#EnableTransactionManagement
public class DBConfig {
#Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false");
config.setUsername("root");
config.setPassword("root");
config.setMaximumPoolSize(20);
HikariDataSource dataSource = new HikariDataSource(config);
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setDataSource(dataSource());
factory.setPackagesToScan("com.example.person");
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
jpaProperties.put("hibernate.hbm2ddl.auto", "update");
factory.setJpaProperties(jpaProperties);
factory.afterPropertiesSet();
return factory.getObject();
}
}
Try to annotate your PersonForm with some Spring annotation like #Component. Or maybe better try to use annotation from vaadin-spring #SpringView.

Environement is Null when I try to Autowire

I am trying to use Environment abstraction & #PropertySource of Spring to load and use properties in my #Configuration annotated classes. However I get Environment as null in my PropertyConfig class as it is accessed from another #Configuration class PersistenceConfig which used it to access the properties. Here is my relevant code :
#Configuration
#PropertySource({ "classpath:/properties/email_${environment}.properties" })
#PropertySource({ "classpath:/properties/appconfig.properties" })
#PropertySource({ "classpath:/properties/ApplicationResources.properties" })
#PropertySource({ "classpath:/properties/Database_${environment}.properties" })
#PropertySource({ "classpath:/properties/log4j.properties" })
#PropertySource({ "classpath:/properties/system.properties" })
public class PropertiesConfig {
#Autowired
private Environment env;
private static final PropertiesAccessor propertyAccessor = new PropertiesConfig().new PropertiesAccessor();
public static String getPopertyValue(String property){
return propertyAccessor.getPropertyValue(property);
}
private class PropertiesAccessor{
public String getPropertyValue(String key){
return env.getProperty(key);
}
}
}
My Other #Configuration annotated class PersistenceConfig is as follows :
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.template"})
public class PersistenceConfig {
#Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String [] {"com.template.domain" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public BasicDataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(PropertiesConfig.getPopertyValue("jdbc.driverClassName"));
dataSource.setUrl(PropertiesConfig.getPopertyValue("jdbc.url"));
dataSource.setUsername(PropertiesConfig.getPopertyValue("jdbc.user"));
dataSource.setPassword(PropertiesConfig.getPopertyValue("jdbc.pass"));
return dataSource;
}
#Bean
public HibernateTransactionManager transactionManager(){
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
Properties hibernateProperties(){
return new Properties() {
{
setProperty("hibernate.hbm2ddl.auto", PropertiesConfig.getPopertyValue("hibernate.hbm2ddl.auto"));
setProperty("hibernate.dialect", PropertiesConfig.getPopertyValue("hibernate.dialect"));
setProperty("hibernate.globally_quoted_identifiers", "true");
}
};
}
}
However I get NullpointerException when dataSource() method of PersistenceConfig tries to retrieve properties using PropertiesConfig.getPopertyValue("jdbc.driverClassName") because env of type Environment is null in PropertyConfig.
I am loading both classes as follows in my WebApplicationInitializer :
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(PropertiesConfig.class,SecurityConfig.class,PersistenceConfig.class,ApplicationConfig.class);
//rootContext.register(ApplicationConfig.class, PersistenceConfig.class, SecurityConfig.class); I have not added security yet
// Manage the life-cycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
dispatcherServlet.register(MvcConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
As far as I understand PersistenceConfig is being loaded first before PropertyConfig. Am I right? Or is there any other reason? How to make this work?
package com.template.config;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;import
org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
#Configuration
#PropertySource({ "classpath:/properties/email_${environment}.properties" })
#PropertySource({ "classpath:/properties/appconfig.properties" })
#PropertySource({ "classpath:/properties/ApplicationResources.properties" })
#PropertySource({ "classpath:/properties/Database_${environment}.properties"
})
#PropertySource({ "classpath:/properties/log4j.properties" })
#PropertySource({ "classpath:/properties/system.properties" })
public class PropertiesConfig {
#Autowired
private Environment env;
private static Environment environment;
#PostConstruct
public void init(){
environment = env;
System.out.println(environment == env);
}
public static String getPopertyValue(String property){
return environment.getProperty(property);
}
}
use #PostConstruct on a method to process what you want .Because you can't get inject bean before spring init container,the inject must be after refresh operation.
eg:
#Component
public class envConfig {
#Autowired
private Environment env;
//something want to get
private String[] profiles;
#PostConstruct
public void init(){
//get the env properties or throw injected bean to init other bean
this.profiles=env.getActiveProfiles();
}
}
I was facing the similar issue. There are many different questions around this problem. There are many answered. However i found the reason in below blog
https://allaboutspringframework.com/spring-fix-null-autowired-field/
In the end of this blog author has concluded the findings which is important.
Spring dependency injection only works with Spring-managed objects or Beans. If the object in which a Bean is getting injected is not a spring managed object, you will get null #Autowired fields. To fix this, make sure only the framework create and manage the related dependencies.

How can I make WebApplicationContext access beans in ApplicationContext?

This is how I try to bootstrap Spring in my Java Web Application:
public class SpringBootstrap implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
final AnnotationConfigApplicationContext rootContext = new AnnotationConfigApplicationContext();
rootContext.register(RootContextConfiguration.class);
final AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(WebContextConfiguration.class);
webContext.setParent(rootContext);
final DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
final ServletRegistration.Dynamic dispatcher = servletContext.addServlet("springDispatcher", dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
final ContextLoaderListener contextLoadListener = new ContextLoaderListener(webContext);
servletContext.addListener(contextLoadListener);
}
}
And RootContextConfiguration and WebContextConfiguration classes are as follows:
#Configuration
#ComponentScan(basePackages = "biz.tugay.janeleven.root")
public class RootContextConfiguration {
}
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "biz.tugay.janeleven.web")
public class WebContextConfiguration {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
return resolver;
}
}
When I try deploying the application to Tomcat and start I will get:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[biz.tugay.janeleven.root.service.AppUserService] found for
dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I am also including the HelloServlet and AppUserService classes here, with their package information:
package biz.tugay.janeleven.root.service;
#Service
public class AppUserService {
public AppUser addAppUser(String name) {
final AppUser appUser = new AppUser(name);
AppUserDB.addUser(appUser);
return appUser;
}
public Collection<AppUser> getAllAppUsers() {
return AppUserDB.getAll();
}
}
package biz.tugay.janeleven.web;
#Controller
#RequestMapping(value = "/")
public class HelloWorldServlet {
#Autowired
private AppUserService appUserService;
#RequestMapping(value = "", method = RequestMethod.GET)
public String helloWorld(Model model) {
final Collection<AppUser> appUserList = appUserService.getAllAppUsers();
model.addAttribute("appUserList", appUserList);
return "hello.jsp";
}
#RequestMapping(value = "", method = RequestMethod.POST)
public String addApplicationUser(#RequestParam("username") String username) {
appUserService.addAppUser(username);
return "redirect:/";
}
}
My expectation is that, WebContextConfiguration should be able to find beans that are managed by RootContextConfiguration since I am calling:
webContext.setParent(rootContext);
during the bootstrap process. But obviously I am missing something.
You are correct that the web context will inherit from the root context, however
you did not include the rootContext when you initialized servletContext.addListener(); see similar code below which will help you fix your issue.
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher",
new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}

Resources