private String message;
#Autowired
private CustomMessageSource messageSource;
#PostConstruct
public void postConstruct() {
message= messageSource.getMessage("warning-message");
logger.log(message);
}
#Component
public class CustomMessageSource extends ReloadableResourceBundleMessageSource {
#Autowired
private ApplicationContext ctx;
public CustomMessageSource() {
Locale.setDefault(Locale.ENGLISH);
}
public String getMessage(String key) {
return ctx.getMessage(key, new Object[] { }, getCurrentLocale());
}
}
in above code , when #PostConstruct is getting executed,I am getting error:
messagesource not initialized - call 'refresh' before accessing
messages via the context failing the applicationContext loading
warning-message is a key in messages.properties file.
On debugging I have found that even though messageSource object is created but probably messages have not loaded causing this error.
if instead of post construct,I use it directly in the execution methods,it works correctly.
Can some one please throw some light on this if this is even possible or may be I am doing anything wrong?
Related
I'm using the latest version of spring and using the caching concept. My (rest) service class seems to not be injected with the caching annotation. If I remove them it works perfectly however I don't use cache which is not what I want.
Application:
#SpringBootApplication
#EnableCaching
public class MyApplication{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("MyCache")));
return cacheManager;
}
The service:
#CacheConfig(cacheNames = "MyCache")
#Service
public class MyServiceImpl implements MyService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final String errormessage = "Error getting books";
#Autowired
private UserRepositoryCrud userRepository;
public MyServiceImpl () {
}
#Override
#Cacheable(value = "MyCache", key = "#description", unless = "#result?.size() > 0")
public final List<Books> getBooks(String description) {
logger.debug("Starting getBooksService");
//service implementation ...
(I also have a Restcontroler that only call this service)
When calling this method getBooks, I got a nullpointer on the logger, but when debugging I realize that everything is null, even the errormessage string...
If I remove the #Cacheable annotation, it then works but I do not have the cache working which is not what I want.
Do you know what can be wrong ?
Thanks a lot,
Guys I found the issue... because the method was final!!! I spent a lot of time to find this!
I have the following configuration class
#org.springframework.context.annotation.Configuration
public class TemplateConfiguration {
#Bean
public Configuration configuration() {
Configuration configuration = new Configuration(new Version(2, 3, 23));
configuration.setClassForTemplateLoading(TemplateConfiguration.class, "/templates/");
configuration.setDefaultEncoding("UTF-8");
configuration.setLocale(Locale.US);
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
return configuration;
}
}
and I use it at the following #service
#Service
public class FreeMarkerService {
#Autowired
private Configuration configuration;
private static final Logger logger = LoggerFactory.getLogger(FreeMarkerService.class);
public String process() {
try {
Template template = configuration.getTemplate("someName");
....
} catch (IOException | TemplateException e) {
logger.error("Error while processing FreeMarker template: " + e);
throw new RuntimeException(e);
}
}
}
but when I try to call process() like
FreeMarkerService f = new FreeMarkerService()
f.process()
I get a null exception cause the configuration Object is null
I want to create an instance using #Autowired and #Configuration annotations
what am I doing wrong?
You should use the Spring instantiated FreeMarkerService object avoiding use of new keyword for objects like Controllers or Services as possible.
For example,
#Service
public class SampleService {
#Autowired
private FreeMarkerService freeMarkerService;
public String callProcess() {
return freeMarkerService.process();
}
}
More details you can find in many posts like this.
This is a member injection:
#Autowired
private static Configuration configuration;
Which spring does after instantiating the bean from its constructor. So at the time you are making that static method call spring has not injected the value.
This is because you are trying to autowire a static field. This is not possible in Spring. Remove static from your Configuration property and it should work.
#Autowired
private Configuration configuration;
#Autowired
private static Configuration configuration;
Why autowired a static field? this is the reason. static member load as class definition load so it is not getting injected value and getting default value which is null.
I am working on a Spring Boot application wherein I am using that application to expose a SOAP webservice. I am using Apache CFX framework for SOAP impl in Spring boot app. I am using Annotation based approach.
I am facing issue in setting the Application Context from the Spring Boot Configuration file in one of the Beans. Below is my code.
#SpringBootApplication
#ComponentScan("com.test")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The configuration file is as below.
#Configuration
public class WebServiceConfiguration {
//All individual bean definitions should go here
#Autowired
ApplicationContext appContext;
#Bean
public ServletRegistrationBean cxfServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/soap-api/*");
}
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean(name="IValidator")
public IValidator getValidator(){
return new Validator();
}
#Bean(name="SOAPprocessImpl")
public IPSoap getService() {
return new SOAPprocessImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), getService());
endpoint.publish("/WS_1.0");
endpoint.setWsdlLocation("process.wsdl");
return endpoint;
}
Now I have the bean SOAPprocessImpl implementation in which I need to get the Application Context so that I can get handle to the Validator bean. I have declared SOAPprocessImpl as a bean in the configuraton file. The code is as below
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
context = ac;
}
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
private IValidator validator = (IValidator) context.getBean("IValidator"); // context is NULL here
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}
So the issue is that when I run the boot application by deploying to the embedded Tomcat then the Application Context is not getting set in the SOAPprocessImpl class even after implementing the ApplicationContextAware. I also tried Autowiring but that also is not working.
Strangely I tried to see if I can get the ApplicationContext in the Configuration file where all the bean are defined. Here it is getting setting properly.
Can anyone help me how to solve this issue. I am new to Spring Boot and may have missed some configutaion. Thanks in advance.
Option(1): To fix the issue, you need to use #Configuration to register your SOAPprocessImpl bean to the Spring container as shown below so that ApplicationContext object can be injected :
#Configuration
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
private IValidator validator;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
SOAPprocessImpl.context = ac;
}
#PostConstruct//use PostConstruct
public void init() {
validator = (IValidator) context.getBean("IValidator");
}
//add your current code
}
The important point is that you can't use the context object until the bean is prepared by the container, so you need to use #PostConstruct method as shown above to initialise your variables.
Option2 (recommended):
The best approach is that you can use #Autowired to inject IValidator object into SOAPprocessImpl as shown below so that you don't need your SOAPprocessImpl bean to be aware of ApplicationContextAware. Spring container will inject the instance for the implementation provided for the IValidator class (provided it is under the packages of #Componentscan).
#Component
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap {
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
#Autowired //spring directly injects this object
private IValidator validator;
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}
I'm new to Spring so I'm just trying to understand how it works. I've developed a simple servletprojectusing spring to manage hibernate framework.
I have a service
#Service("service")
#Transactional
public class CdServiceImpl {
#Autowired
private HibernateUtility hibernateutility;
public int saveCd(CD cd) {
return hibernateutility.saveCd(cd);
}
public List getCd(String searchedCd) {
return hibernateutility.getCd(searchedCd);
}
public List getAllCd() {
return hibernateutility.getAllCd();
}
public void deleteCd(int id) {
hibernateutility.deleteCd(id);
}
public User getUser(String username, String password) {
return hibernateutility.getUser(username, password);
}
}
And then I use it in the servlet
context.scan("it.project");
context.refresh();
CdServiceImpl service = (CdServiceImpl) context.getBean("service");
context.register(ApplicationContextConfig.class);
context.refresh();
1) It works but I have two question. It is the right way to work?
2) I've tried to set a field in the servlet like:
#Autowired
private CdServiceImpl service
and then I remove the context.scan ecc part and it gave me nullpointerexception. Why?
Doing that I also defined a new bean
#Bean
public CdServiceImpl getCdServiceImpl() {
return new CdServiceImpl();
}
Why it doesn't work? I know that maybe this is a noob question but I'm tryingto figure out how spring works
Basically as soon as you start doing things like new **ApplicationContext you need to scratch your head, take 2 steps away from the keyboard and think if you really want to do this. In 99% of the cases this isn't what you want or at least should do.
Instead have the ContextLoaderListener load your configuration. Assuming you don't have a web.xml use the the AbstractContextLoaderInitializer base class.
public ApplicationInitializer extends AbstractContextLoaderInitializer {
protected WebApplicationContext createApplicationContext() {
return new AnnotationConfigWebApplicationContext(ApplicationContextConfig.class);
}
}
Note: As this is for bootstrapping your application you need to create the the context. You could also use AbstractAnnotationConfigDispatcherServletInitializer which eliminates this need, but also creates a DispatcherServlet which you don't need.
Now that your configuration is automatically loaded you can use the WebApplicationContextUtils to get the context to do the lookup. Do this in the init method of your servlet.
public class YourServlet extends GenericServlet {
private CdServiceImpl service;
public void init() throws ServletException {
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
service = ctx.getBean(CdServiceImpl.class);
}
}
Now you initialize the bean once and don't need to handle anything anymore. You could also use #Autowired and manuallly have it injected.
public class YourServlet extends GenericServlet {
#Autowired
private CdServiceImpl service;
public void init() throws ServletException {
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
ctx.getAutowireCapableBeanFactory().autowireBean(this);
}
}
I have the Enum:
public enum EmployeeErrorCode {
DELETE_SUCCESS,
//... Other enumerators
#Override
public String toString(){
ApplicationContext ctx = ContextLoader
.getCurrentWebApplicationContext();
MessageSource messageSource = (MessageSource) ctx
.getBean("messageSource"); //How to avoid this?
switch (this) {
case DELETE_SUCCESS:
return messageSource.getMessage("deleteEmployee.success",
null, LocaleContextHolder.getLocale());
//... Other cases
default:
return null;
}
}
}
In the toString nethod I specified the messages for any Enumerator, but I used getBean method to programmatically get the appropriate bean. How can I avoid that?
I tried to inject the bean via
#Autowired
MessageSource messageSource;
but it didn't work. In fact, messageSource was just null. Is there a way to do that corretly at all?
If MessageSource is a bean that opens a properties file, then for example if your properties file is called Messages.properties, then you can use
ResourceBundle bundle = ResourceBundle.getBundle("Messages", LocaleContextHolder.getLocale());
String message = bundle.getString("deleteEmployee.success");
EDIT: Another possible method is to inject the MessageSource into your enums (idea from my solution at Java Generics and Enum, loss of template parameters ), like so:
public enum EmployeeErrorCode {
DELETE_SUCCESS {
#Override
public String toString() {
return messageSource.getMessage("deleteEmployee.success", null, LocaleContextHolder.getLocale());
}
},
//... Other enumerators
private MessageSource messageSource;
static class EnumInitializer {
#Autowired
private MessageSource messageSource;
#PostConstruct
public void init() {
for(EmployeeErrorCode errorCode : EmployeeErrorCode.values() {
errorCode.messageSource = getMessageSource();
}
}
public MessageSource getMessageSource() {
return messageSource;
}
}
}
But I think the other one is a bit cleaner.