I have a Springboot application as follows:
#SpringBootApplication
#ImportResource("classpath:/config/applicationContext.xml")
public class TaxBatchMain {
#Autowired
TaxIdService taxIdService;
private static final Logger LOGGER = LogManager.getLogger(TaxBatchMain.class);
public static void main(String[] args) {
new SpringApplicationBuilder(TaxBatchMain.class).web(false).run(args);
TaxBatchMain taxBatchMain = new TaxBatchMain();
}
public TaxBatchMain() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
#PostConstruct
public void checkForTransactions() {
try {
////
String tab = "someother content";
String footer = taxIdService.formatFooter();
////
////
}catch(){
//////////
}
}
}
TaxIdServiceImpl class is as follows:
#Service
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class TaxIdServiceImpl implements TaxIdService {
#Autowired
private ServletContext servletContext;
private String formatFooter(String footer) {
String[] searchList = {"<ENVIRONMENT_NAME>", "<MS_ENV_NAME>"};
String[] replacementList = {(String) servletContext.getAttribute(ServletContextKey.EMAIL_HOST_NAME.name()),
(String) servletContext.getAttribute(ServletContextKey.MS_EMAIL_HOST_NAME.name())};
return StringUtils.replaceEach(footer, searchList, replacementList);
}
}
Application Context looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"....................///
<context:annotation-config />
<context:property-placeholder location="classpath:/config.properties" />
<util:properties id="configProperties" location="classpath:/config.properties" />
<!-- <context:property-placeholder location="classpath:data/application.properties"/> -->
<context:component-scan base-package="com.tax.main" />
<context:component-scan base-package="com.tax.service" />
<context:component-scan base-package="com.tax.model" />
<context:component-scan base-package="com.tax.mapper" />
<context:component-scan base-package="com.tax.util" />
/////
When I run the main class i get foll. error
APPLICATION FAILED TO START
Description:
Field servletContext in com.tax.service.TaxIdServiceImpl required a bean of type 'javax.servlet.ServletContext' that could not be found.
Action:
Consider defining a bean of type 'javax.servlet.ServletContext' in your configuration.
Try enabling webEnvironment. It appears your SpringApplicationBuilder is not enabled with web environment.
new SpringApplicationBuilder(TaxBatchMain.class).web(true).run(args);
Since you are using spring-boot you can consider using Annotation based approach rather xml based.
Related
I have a xml bean file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="helloWorld" class="com.a.b.HelloWorld">
<property name="attr1" value="Attr1 from XML"></property>
</bean>
<bean id="helloWorld2" class="com.a.b.HelloWorld2">
<property name="attr2" value="Attr2 from XML"></property>
</bean>
</beans>
And I have use constructor autowiring like this
public class HelloWorld2{
private String attr2;
public void setAttr2(String message){
this.attr2 = message;
}
public void getAttr2(){
System.out.println("getAttr2 == " + attr2);
}
}
public class HelloWorld{
private String attr1;
private HelloWorld2 helloWorld2;
public HelloWorld(){
}
#Autowired
public HelloWorld(HelloWorld2 helloWorld2){
System.out.println("hhh");
this.helloWorld2 = helloWorld2;
}
public void setAttr1(String message){
this.attr1 = message;
}
public void getAttr1(){
System.out.println("getAttr1 == " + attr1);
}
public void getH(){
helloWorld2.getAttr2();
}
}
And autowiring is working fine.
Now I want to move my beans to Configuation class.
But then how to move the code so as autowiring works?
I have tried like this, but its not working
#Configuration
public class Config {
#Bean
public HelloWorld helloWorld(){
HelloWorld a = new HelloWorld();
a.setAttr1("Demo Attr1");
return a;
}
#Bean
public HelloWorld2 helloWorld2(){
HelloWorld2 a = new HelloWorld2();
a.setAttr2("Demo Attr2");
return a;
}
}
I think what you want to achieve is the injection of a HelloWorld2 instance into the method that creates the HelloWorld #Bean?
This should do it:
#Configuration
public class Config {
#Bean
public HelloWorld helloWorld(HelloWorld2 helloWorld2){
HelloWorld a = new HelloWorld(helloWorld2);
a.setAttr1("Demo Attr1");
return a;
}
#Bean
public HelloWorld2 helloWorld2(){
HelloWorld2 a = new HelloWorld2();
a.setAttr2("Demo Attr2");
return a;
}
}
This might be a duplication of these questions:
Understanding Spring Autowired usage
Converting Spring XML file to Spring configuration class
A class
public class A {
private String name;
public A() {
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
BeanFactory class
public class BeanFactory implements InitializingBean, DisposableBean{
private A a;
public BeanFactory(){
}
public BeanFactory(A a){
this.a = a;
}
public void printAName(){
System.out.println("Class BeanFactory: beanFactory.printAName -> a.getName() = " + a.getName());
}
}
Main
public class Main {
public static void main(String[] args) {
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"ApplicationContext.xml");
BeanFactory beanFactory = applicationContext.getBean("beanFactory",
BeanFactory.class);
beanFactory.printAName();
}
}
ApplicationContext
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="beanFactory" class="testSpring.BeanFactory">
<constructor-arg ref="a1"/>
</bean>
<bean id="a1" class="testSpring.A">
<property name="name" value="I am A!"></property>
</bean>
</beans>
Result of run: Class BeanFactory: beanFactory.printAName -> a.getName() = I am A!
Like you can see, here I don't use no annotation. But the code works thanks to xml file.
So xml doesn't need annotation..? Can I use one or the other?
If I would use, in this application, the annotation (#Autowired for example) instead of bean xml, it's possible? Can you show me how?
Or the annotation must require xml reference?
So.. annotation and xml must be used together? Thanks
You should use annotation configuration, this is the idea
#Component
class Bean1 {
public Bean1() {
System.out.println(getClass());
}
}
#Configuration
#ComponentScan("test")
public class Config {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
}
}
For details see Spring docs
I'm new with Spring MVC and I'm doing some tests. I was trying to find some answers about this issues, but most of them make references to Spring 3.11 and I'm using the last release: 4.1.6.
I want to load a ".properties" file when the application starts, and use the information in it to create a bean to access it in all the context of the app.
So far, I reach to load the file in the servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
...
<context:property-placeholder location="classpath*:resources/Resources.properties" />
</beans:beans>
I think (not really sure) that I correctly declared the bean in the root-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="Resources" class="ar.com.violenciaesmentir.blog.resources.ResourcesDB"/>
</beans>
And I also think I made the bean correctly, but I don't really know if the annotations are right:
package ar.com.violenciaesmentir.blog.resources;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
#Service
public class ResourcesDB {
#Value("DB.NAME")
private String name;
#Value("DB.TYPE")
private String type;
#Value("DB.USER")
private String user;
#Value("DB.PASS")
private String pass;
#Value("DB.DRIVER")
private String driver;
#Value("DB.URL")
private String url;
#Value("DB.MAXACTIVE")
private String maxActive;
#Value("DB.MAXIDLE")
private String maxIdle;
#Value("DB.MAXWAIT")
private String maxWait;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMaxActive() {
return maxActive;
}
public void setMaxActive(String maxActive) {
this.maxActive = maxActive;
}
public String getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(String maxIdle) {
this.maxIdle = maxIdle;
}
public String getMaxWait() {
return maxWait;
}
public void setMaxWait(String maxWait) {
this.maxWait = maxWait;
}
}
My ".properties" file:
DB.NAME = jdbc/Blog
DB.TYPE = javax.sql.DataSource
DB.USER = blog
DB.PASS = blog
DB.DRIVER = oracle.jdbc.driver.OracleDriver
DB.URL = jdbc:oracle:thin:#localhost:1521:xe
DB.MAXACTIVE = 20
DB.MAXIDLE = 5
DB.MAXWAIT = 10000
I think the reference is ok because it gave me troubles when starting the server, saying that it couldn't find the property for "name", but I was doing the annotation wrong and then I fixed.
What I want is to have that bean initialized and be avaible to have an attribute in the DB class like:
#ManagedAttribute
private ResourcesDB resources;
...
public void foo() {
String dbName = resources.getName();
}
When I try it, resources is null. What I'm doing wrong?
-----UPDATE-----
Ok, I could solve the problem doing some try&fail with the answers given. First of all, I corrected the #Value like ("${DB.NAME}") and added a value to the service annotation #Service(value="Resources").
Then, the only change I got to do was in the servlet-context.xml. Instead of:
<context:property-placeholder location="classpath*:resources/Resources.properties" />
I used:
<beans:bean id="configuracion" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location" value="classpath:Resources.properties"/>
</beans:bean>
And used #Autowire instead of #ManagedBean to access the bean.
There are 2 things flawed in your code.
Your #Value expressions are wrong
Your <context:property-placeholder /> must be in the same context as the beans
When using #Value you have to use placeholders, by default ${property name} you are just using a name. So update your annotations to reflect that. I.e. #Value("${DB.NAME}.
Next you have defined <context:property-placeholder /> in the context loaded by the DispatcherServlet whereas your beans are loaded by the ContextLoaderListener. The property placeholder bean is a BeanFactoryPostProcessor and it will only operate on bean definitions loaded in the same context. Basically your bean definition are in the parent context and your placeholder in the child context.
To fix move <context:property-placeholder /> to the same context where you bean is defined in.
Instead of #ManagedAttribute which is a JSF annotation use #Autowired or #Inject. And if you don't have a <context:component-scan /> add a <context:annotation-driven />.
Your #Value syntax is incorrect. It should be #Value("${DB.NAME}").
You might also need to add this to your XML config:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:resources/Resources.properties" />
</bean>
The value on the location may vary, not sure on how you are structuring and building your artifacts.
I am learning SPRING and this is not web application code; I am getting NLP while using #Autowired annotation in field level.
Q1) Please help what is wrong?
Q2) If i have #Scope annotation at the class level; do i still need at XML bean level?
#Controller
#Scope(value = BeanDefinition.SCOPE_SINGLETON)
public class StreamingController implements psConsolePortListener.Implementation{
#Autowired
#Qualifier("scMgr")
private StreamingControllerManager streamingMgr = null;
public static void main(String[] args) {
logger.info("StreamingController testing");
XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource(BEAN_FILE));
StreamingController obj = (StreamingController) factory.getBean("streamingController");
obj.streamingMgr.test();
}
}
#Service
#Scope(value = BeanDefinition.SCOPE_SINGLETON)
#Qualifier("scMgr")
public class StreamingControllerManager {
/** Logger */
private static final Logger logger = LoggerFactory.getLogger(StreamingControllerManager.class);
private StreamingControllerManager(){
logger.info("StreamingControllerManager is called!!");
}
public void test(){
logger.info("StreamingControllerManager test!!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:annotation-config />
<context:component-scan base-package="com.xxx.streamingController"/>
<bean id="scMgr" class="com.xxx.streamingController.StreamingControllerManager">
</bean>
<bean id="streamingController" class="com.xxx.streamingController.StreamingController">
</bean>
</beans>
Output:
Exception in thread "main" java.lang.NullPointerException
at com.pactolus.streamingController.StreamingController.main(
Use an ApplicationContext instead of a BeanFactory.
public static void main(String[] args) {
logger.info("StreamingController testing");
ApplicationContext ctx = new ClassPathXmlApplicationContext(BEAN_FILE);
StreamingController obj = (StreamingController) ctx.getBean("streamingController");
obj.streamingMgr.test();
}
Also remove <context:annotation-config /> that is already impllied by <context:component-scan /> and remove the bean declarations. You are using component-scanning so no need to declare the beans.
Basically leaving you with.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:component-scan base-package="com.xxx"/>
</beans>
In spring JavaConfig, I can define property source and inject into Environment
#PropertySource("classpath:application.properties")
#Inject private Environment environment;
How do I do that if in xml?
I am using context:property-placeholder, and on the JavaConfig class #ImportResource to import the xml. But I cannot retrieve property defined in the properties file using environment.getProperty("xx")
<context:property-placeholder location="classpath:application.properties" />
AFAIK, there is no way of doing this by pure XML. Anyways, here is a little code I did this morning:
First, the test:
public class EnvironmentTests {
#Test
public void addPropertiesToEnvironmentTest() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"testContext.xml");
Environment environment = context.getEnvironment();
String world = environment.getProperty("hello");
assertNotNull(world);
assertEquals("world", world);
System.out.println("Hello " + world);
}
}
Then the class:
public class PropertySourcesAdderBean implements InitializingBean,
ApplicationContextAware {
private Properties properties;
private ApplicationContext applicationContext;
public PropertySourcesAdderBean() {
}
public void afterPropertiesSet() throws Exception {
PropertiesPropertySource propertySource = new PropertiesPropertySource(
"helloWorldProps", this.properties);
ConfigurableEnvironment environment = (ConfigurableEnvironment) this.applicationContext
.getEnvironment();
environment.getPropertySources().addFirst(propertySource);
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
And the testContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<util:properties id="props" location="classpath:props.properties" />
<bean id="propertySources" class="org.mael.stackoverflow.testing.PropertySourcesAdderBean">
<property name="properties" ref="props" />
</bean>
</beans>
And the props.properties file:
hello=world
It is pretty simple, just use a ApplicationContextAware bean and get the ConfigurableEnvironment from the (Web)ApplicationContext. Then just add a PropertiesPropertySource to the MutablePropertySources
If what you need is just access the property "xx" of the file "application.properties", you can accomplish that without Java code by declaring the following bean in your xml file:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="application.properties"/>
</bean>
Then if you want to inject the property in a bean just reference it as a variable:
<bean id="myBean" class="foo.bar.MyClass">
<property name="myProperty" value="${xx}"/>
</bean>