Can't get message from MessageSource outside Controller - java

Everything works fine when I try to get messages in a #Controller class, but when I try
to achieve the same in a #Service or #Component class I receive the following error:
org.springframework.context.NoSuchMessageException:
No message found under code 'email.ativacao.title' for locale 'pt_BR'.
My Controller:
#Controller
public class TestController {
#Autowired
TestService service;
#Autowired
TestComponent component;
#Autowired
private MessageSource message;
#RequestMapping(value = "/send", method = RequestMethod.GET)
public String go() {
String message = message.getMessage
("email.ativacao.title", null, new Locale("pt", "BR"));
service.getMessage();
component.getMessage();
return "signsucess";
}
}
My Service:
#Service
public class TestService {
#Autowired
private MessageSource message;
public void getMessage() {
//Error
String message = message.
getMessage("email.ativacao.title", null, new Locale("pt", "BR"));
}
}
My Component:
#Component
public class TestComponent {
#Autowired
private MessageSource message;
public void getMessage() {
//Error
String message = message.
getMessage("email.ativacao.title", null, new Locale("pt", "BR"));
}
}
My config:
<!-- i18n -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.
LocaleChangeInterceptor" p:paramName="lang"/>
</mvc:interceptors>
<!-- Mesage Source Config -->
<bean id="messageSource"
class="org.springframework.context.support.
ReloadableResourceBundleMessageSource" p:fallbackToSystemLocale="true" >
<property name="basename" value="WEB-INF/i18n/messages" />
</bean>
<!-- Mapeia o cookie que irá salvar as opções de idioma -->
<bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
id="localeResolver" p:cookieName="locale"/>
MessageSource is not null on both #Service and #Component, but they're not able to
get the message (Exception above). My properties:
WebContent/WEB-INF/i18n
messages_pt_BR
messages_en_US
I really can't find the problem. Any suggestion to solve this? Thanks.

From what you were describing, I guess controller bean and messageSource were declared in same context. so then can find each other.
if your service bean and controller bean are not declared in same context, your service cannot find the messageSource.
same context doesn't mean same file. your one.xml could include two.xml.
anyway, if it worked for you, it's good.

Related

How to move XML bean definition to #Configuration annotated class

I am new to Spring, I am working in moving some bean definitions from XML to #Configuration Class.
Here is one of the beans I am struggling with:
<bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="connectionFactory"/>
<jms:listener-container container-type="default"
connection-factory="connectionFactory"
acknowledge="auto">
<jms:listener destination="YOURQUEUENAME" ref="theListenerClassYouAreUsing" />
</jms:listener-container>
How would that look in a #Configuration class, thanks.
So far I have this
#Bean("myContainerFactory")
public JmsListenerContainerFactory myContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
ConnectionFactory connectionFactory = pooledConnectionFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPubSubDomain(false);
return factory;
}
I am missing the destination set, no idea how to do it.
You have to add a listener as well, see for example Annotation-driven Listener Endpoints:
#Component
public class MyService {
#JmsListener(destination = "YOURQUEUENAME", containerFactory = "myContainerFactory")
public void myListener(String data) { ... }
}

How to define which bean to autowire in Spring

I have 2 beans of the same type:
#Component("beanA")
public class BeanA implements BaseBean {}
#Component("beanB")
public class BeanB implements BaseBean {}
This type is used in my service:
#Service
public class MyService {
#Autowired
private BaseBean baseBean;
}
Now I want to use both possible MyService beans in another service
#Service
public class AnotherService {
#Autowired
private MyService myServiceWithBeanA;
#Autowired
private MyService myServiceWithBeanB;
}
How can I achieve that? Maybe I should take another approach?
I know how to do it in XML-based beans configuration. How can I do it using annotations?
<bean id="AnotherService" class="AnotherService">
<property name="myServiceWithBeanA" ref="myServiceWithBeanA" />
<property name="myServiceWithBeanB" ref="myServiceWithBeanB" />
</bean>
<bean id="myServiceWithBeanA" class="MyService">
<property name="baseBean" ref="beanA" />
</bean>
<bean id="myServiceWithBeanB" class="MyService">
<property name="baseBean" ref="beanB" />
</bean>
<bean id="beanA" class="BeanA" />
<bean id="beanB" class="BeanB" />
The problem is that MyService is annotated with #Service. This means that it is a singleton - only one instance will be created.
In order to create multiple instances, you need to expose two #Beans via configuration.
#Configuration
public class MyServiceConfig {
#Bean
public MyService serviceA(#Qualifier("beanA") beanA) {
return new MyService(beanA);
}
#Bean
public MyService serviceB(#Qualifier("beanB") beanB) {
return new MyService(beanB);
}
}
MyService would become
public class MyService {
private BaseBean baseBean;
public MyService(BaseBean baseBean) {
this.baseBean = baseBean;
}
}
You can then pass all of these to the other service with qualifiers
#Service
public class AnotherService {
#Autowired
#Qualifier("serviceA")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("serviceB")
private MyService myServiceWithBeanB;
}
Using the #Qualifier annotation you can specify which bean you want to autowire.
#Service
public class AnotherService {
#Autowired
#Qualifier("beanA")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("beanB")
private MyService myServiceWithBeanB;
}
Hope this helps.
In your xml bean definition add the these tags <qualifier value="name"/>.
<bean id="myServiceWithBeanA" class="MyService">
<qualifier value="A"/>
<property name="baseBean" ref="beanA" />
</bean>
<bean id="myServiceWithBeanB" class="MyService">
<qualifier value="B"/>
<property name="baseBean" ref="beanB" />
</bean>
And then you can get them by using Qualifier annotation like this:
#Autowired
#Qualifier("A")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("B")
private MyService myServiceWithBeanB;
You also can do more stuff than that.
Have a look at the documentation on the following link:
Qualifier documentaiton
Not everything can be done with annotations. In cases where you need to create multiple instance of a bean but with different arguments you have to fallback to #Configuration and define those beans as you would in the XML config.
#Configuration
public class AppConfig {
#Bean
public MyService myServiceWithBeanA(BeanA beanA) {
return new MyService(beanA);
}
#Bean
public MyService myserviceWithBeanB(BeanB beanB) {
return new MyService(beanB);
}
}
Now just tell AnotherService to expect MyService twice with matching bean names as name of the bean defining method is its default qualifier.
#Service
public class AnotherService {
#Autowired
private MyService myServiceWithBeanA;
#Autowired
private MyService myServiceWithBeanB;
}

injecting different implementation of service bean in same controller from different servlet

I am new to annotation based controller. I have two servlet like this:
pathA-servlet for url: pathA/*
pathB-servlet for url: pathB/*
And I have a controller like:
public class MyController extends SimpleFormController {
private MyService myService;
}
And two service implementation:
public class MyService1 implements MyService {
}
public class MyService2 implements MyService {
}
And in pathA-servlet:
<bean name="/doSomeThing" class="MyController">
<property name="myService" ref="myService"/>
</bean>
<bean id="myService" class="MyService1"/>
And in pathB-servlet:
<bean name="/doSomeThing" class="MyController">
<property name="myService" ref="myService"/>
</bean>
<bean id="myService" class="MyService2"/>
Now, I am trying to do the same with annotation based controller using: #Controller, #RequestMapping. How can I do that?
Here is a sample #Controller. This is a rest endpoint, you can access it with
#Controller
#RequestMapping(method = RequestMethod.POST, value = "/my")
public class CopyOfMyController {
#Autowired
private MyService service;
#RequestMapping(method = RequestMethod.POST, value = "/hib")
public void haha(#ResponseBody RequestDTO dto) {
service.doSomething(dto);
}
}
you can hit it with
Dto dto = new Dto();
dto.setPhone("12313");
RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(new URI("http://localhost:8080/my/hib"), dto, Dto.class);
It's very simple. In your controller, first add the #Controller annotation. This annotation simply says that this class will be a Spring controller that will be able to handle HTTP Requests based on the url mapping defined in the methods of your controller.
Also add an #Autowired annotation for the service attribute. Since there is 2 implementations of MyService, add the #Qualifier by passing the bean name because Spring would unable to choose which bean to inject otherwise.
So you can do something like this :
#Controller
public class MyController {
#Autowired
#Qualifier("bean1") // This should be bean1
private MyService myService1;
#Autowired
#Qualifier("bean2")
private MyService myService2;
#RequestMapping(value = "/doSomeThing1", method = RequestMethod.GET)
public String doSomething(){
return myService1.doSomething();
}
#RequestMapping(value = "/doSomeThing2", method = RequestMethod.GET)
public String doSomething(){
return myService2.doSomething();
}
}

Bean autowire fail when running tests only

Hopefully someone might have the answer for this problem.
I have a autowire problem occuring when I run my tests but not else.
The exception is pretty clear as it says 'myField' is missing. The field is however inherited from a base class. I cannot find the answer to my problem anywhere so I will try my luck here.
The exception
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'myService': Injection of autowired dependencies failed;
nested exception is java.lang.NoSuchFieldError: myField
My base class
public abstract class CommonStuff {
protected String myField; // the one thats gone missing
public abstract void setMyField(String myField);
}
My service
#Service("myService")
public class MyService extends CommonStuff {
#Value("${myProperty.myField}")
public void setMyField(String myField) {
this.myField = myField;
}
...
}
My controller
#Controller
public class MyController {
#Autowired
private MyService myService;
public void setMyService(MyService myService) {
this.myService = myService;
}
...
}
My application-context.xml
Nothing seems to be left out.
<context:component-scan base-package="com.myapp" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:my.properties</value>
<value>classpath:myother.properties</value>
</list>
</property>
</bean>
my.properties
myProperty.myField=some value
My test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:application-context.xml" })
public class MyControllerTest {
#Autowired
MyController myController;
#Mock
MyService myService;
#Test
public void myServiceTest() {
// do stuff with myService
}
...
}
The problem
As I mentioned the code runs fine but a spring has trouble autowiring whenever I try to run the test.
The problem is not the test but the wiring when starting the test. Somehow spring cannot find myField from the abstract CommonStuff class so it says that MyService do not have the field.
If needed I can post the full stacktrace but I think the essense of the exception is already here.
I gave up and moved the myField back into the service and skipped the setMyField.
This is how it is now.
Base class
public abstract class CommonStuff {
public abstract String getMyField();
public void doCommonStuff() {
// use getMyField()
}
}
My service
#Service("myService")
public class MyService extends CommonStuff {
#Value("${myProperty.myField}")
private String myField;
#Override
public String getMyField() {
return myField;
}
...
}
This solves what I wanted since I now have access to myField from CommonStuff.

dependency Injection by annotation

I am a new user of spring. I am trying to achieve dependency injection by annotation. My
beans.xml is :-
<!-- Add your classes base package here -->
<context:component-scan base-package="com.springaction.chapter01"/>
<bean id="greeting" class="com.springaction.chapter01.GreetingImpl">
<property name="greeting">
<value>Naveen Jakad</value>
</property>
</bean>
bean which I want to inject is:-
package com.springaction.chapter01;
import org.springframework.stereotype.Service;
#Service
public class InjectBean {
private int id;
private String name;
public InjectBean() {
super();
}
//setter getter of above instance variables..
}
and the bean in which I want to inject above bean is :-
package com.springaction.chapter01;
import org.springframework.beans.factory.annotation.Autowired;
public class GreetingImpl implements Greeting {
private String greeting;
#Autowired
private InjectBean myBean;
public GreetingImpl() {
super();
}
public GreetingImpl(String greeting) {
super();
this.greeting = greeting;
}
public void setGreeting(String greeting) {
this.greeting = greeting;
}
#Override
public void sayGreeting() {
System.out.println(greeting + " " + myBean);
}
}
so when I test the above code by :-
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("config.xml"));
Greeting greeting = (Greeting)beanFactory.getBean("greeting");
greeting.sayGreeting();
I get the output "Naveen Jakad null", means in nutshell I am not able to achieve my target. So please help me out and let me know where I making mistake
if you want to inject by #Autowired you don't need to config it in xml :)
You need to set
<mvc:annotation-driven />
<context:component-scan base-package="com.your.base.package" />
That way spring will know to check for annotations
With Fixus solution you do not need the xml file where you define the "greeting" bean:
Just add:
#Component // or #Service if it's also a service
public class GreetingImpl implements Greeting {
This way you do not need to define your beans in the xml file.
If you use Junit test, you just inject the class to test (e.g "Greeting") in your MyJunitClass and have your context set to the one with the annotation-driven and component -scan definition.
You can see that doc to configure your JUnit tests:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html#integration-testing-annotations

Categories