#Autowired in class - java

I have trouble with #Autowired annotation
autoWiredLocallyTest() passes
autoWireAtClassTest() failed
Here is my test cases:
/**
* Spring Autowired test.
*/
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiredTest {
#Autowired
private ActionBeans localBeans;
#Test
public void autoWiredLocallyTest(){
//pre-test
Assert.assertNotNull(localBeans);
}
#Test
public void autoWireAtClassTest(){
TestClazz t = new TestClazz();
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
}
TestClazz is:
public class TestClazz {
#Autowired
#Qualifier("actions")
private ActionBeans tempowieBiny;
public boolean isAutowired(){
return(this.tempowieBiny!=null);
}
}
applicationContext.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">
<import resource="actions.xml" />
<import resource="datasources.xml" />
</beans>
actions.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">
<bean id='actions' class="net.virtalab.jsonio.configuration.actions.ActionBeans" scope="singleton">
<qualifier value="actions" />
</bean>
</beans>
What was made wrong or not done, but required to do?
I using Spring 3.2.5-RELEASE.

You are instantiating TestClazz using the new operator (TestClazz t = new TestClazz();). You need to load it from your spring context if you want the #autowired beans to be properly initialised.
Try:
#Autowired
ApplicationContext testContext;
#Test
public void autoWireAtClassTest(){
// TestClazz t = new TestClazz();
TestClazz t = (TestClazz)testContext.getBean(TestClazz.class);
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}

The problem here is that you're creating new TestClazz object every time. Autowire it instead:
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiredTest {
#Autowired
private ActionBeans localBeans;
// Added here
#Autowired
private TestClazz t;
#Test
public void autoWiredLocallyTest(){
//pre-test
Assert.assertNotNull(localBeans);
}
#Test
public void autoWireAtClassTest(){
//TestClazz t = new TestClazz(); COMMENTED OUT
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
}

Related

Constructor works fine with and without #Autowired

I have tennisCoach object created by Spring framework:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml") ;
Coach theCoach = context.getBean("tennisCoach", Coach.class);
Can't understand why I need #Autowired annotation in TennisCoach constructor in code below. It works fine with and without #Autowired annotation.
#Component
public class TennisCoach implements Coach {
private FortuneService fortuneService;
#Autowired
public TennisCoach(FortuneService theFortuneService) {
fortuneService = theFortuneService;
}
#Override
public String getDailyWorkout() {
return "Practice your backhand volley";
}
#Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
UPD
Content of applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="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:component-scan base-package="com.luv2code.springdemo"></context:component-scan>
</beans>
From #Autowired Javadoc:
If a class only declares a single constructor to begin with, it will always be used, even if not annotated.
Since Spring 4.3 you don’t need the #Autowired annotation as soon as you have the only constructor in your class.
Here #Autowired is used for constructor injection. TennisCoach has a dependency on FortuneService and it is injected through constructor. I'm not sure how you have configured beans in applicationContext.xml

SpringBoot define custome annotation include #Configuration #ImportResource

I'm try to define a custome annotation include #Configuration and #ImportResource
but #ImportResource doesn't work
Any suggestions?
#Documented
#Configuration
#ImportResource
#Target({ElementType.TYPE})
#Order(Ordered.HIGHEST_PRECEDENCE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EnableXXConfiguration {
#AliasFor(annotation = ImportResource.class , attribute = "value")
String[] value() default {};
}
#ImportResource contains two attributes value and locations. The value attribute is ultimately alias for locations attribute so using either of the aliases works fine. Keeping your Custom annotation(EnableXXConfiguration) declaration (the one using value attribute) as it, use below code snippet.
#EnableXXConfiguration(value = { "context1.xml", "com/example/stackoverflow/context2.xml"})
public class DemoApp {
#Autowired
private BeanA beanA;
#Autowired
private BeanB beanB;
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoApp.class);
DemoApp demoAppObj = (DemoApp) context.getBean("demoApp");
System.out.println("BeanA member: " + demoAppObj.getBeanA());
System.out.println("BeanB member: " + demoAppObj.getBeanB());
}
public BeanA getBeanA() {
return beanA;
}
public BeanB getBeanB() {
return beanB;
}
}
Assume we are using two xmlss placed at two different locations. context1.xml is placed in resource folder(src/main/resource) and context2.xml is placed at any other location (here at: src/main/java/com/example/stackoverflow)
context1.xml
<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">
<bean id="beanA" class="com.example.stackoverflow.BeanA" />
</beans>
context2.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">
<bean id="beanB" class="com.example.stackoverflow.BeanB" />
</beans>

transactional doesn't rollback

I use spring 4.3.9.RELEASE
Some configs and code:
#Configuration
#EnableTransactionManagement
public class PersistenceContext {
#Autowired
private DbConfiguration dbConfiguration;
#Bean(destroyMethod = "close")
public DataSource dataSource() {
final BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass(dbConfiguration.getDriverClassName());
dataSource.setJdbcUrl(dbConfiguration.getUrl());
dataSource.setUsername(dbConfiguration.getUsername());
dataSource.setPassword(dbConfiguration.getPassword());
dataSource.setIdleConnectionTestPeriodInMinutes(dbConfiguration.getIdleConnectionTestPeriod());
dataSource.setIdleMaxAgeInMinutes(dbConfiguration.getIdleMaxAgeInMinutes());
dataSource.setMaxConnectionsPerPartition(dbConfiguration.getMaxConnectionsPerPartition());
dataSource.setMinConnectionsPerPartition(dbConfiguration.getMinConnectionsPerPartition());
dataSource.setPartitionCount(dbConfiguration.getPartitionCount());
dataSource.setAcquireIncrement(dbConfiguration.getAcquireIncrement());
dataSource.setStatementsCacheSize(dbConfiguration.getStatementsCacheSize());
return dataSource;
}
#Bean(name = "txManager")
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
servlet:
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:annotation-config/>
<context:component-scan base-package="ru.org.*"/>
<tx:annotation-driven transaction-manager="txManager" />
<mvc:annotation-driven />
</beans>
WebConfig:
#Configuration
#EnableScheduling
#EnableWebMvc
#ComponentScan({"ru.org.*"})
#EnableTransactionManagement
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public MainHandler mainHandler() {
return new MainHandler();
}
}
handler:
public class MainHandler extends AbstractUrlHandlerMapping {
#Autowired
private DataSource dataSource;
protected Object getHandlerInternal(final HttpServletRequest request) throws Exception {
transactionalTest();
}
#Transactional(transactionManager = "txManager")
private void transactionalTest() {
final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute("INSERT INTO marks(score) VALUES (1);");
jdbcTemplate.execute("IN3ERT INTO marks(score) VALUES (1);");
}
}
It throws an exception but no rollback happened.
Also I tried to use rollbackFor-param and throws exactly that exception.
Any ideas?
There are two major rules of #Transaction annotation you must keep in mind
#Transaction will work if the annotated method is not declared in
the same class that invokes it (True for default Spring Proxy AOP).
#Transaction will work if annotated on a public method. It will always
be ignored if the method is private, protected or package-visible.
So what you should do
Delcare a public transactionalTest() method in a #Service annotated class and then call it in MainHandler class

How to use #Required annotation in setter injection in spring?

#required annotation usage. I tried giving this above setter method and tried to find the bean from context without setting this dependency. I got the object with the dependency is set null, my expectation was spring will throw some exception. Please guide me where I am doing wrong?
#Required to make it mandatory that the dependency has to be injected
Let us example:
We need to use RequiredAnnotationPostProcessor which checks whether #Required dependencies have been injected or not
public class BankService {
private CustomerService customerService;
private BillPaymentService billPaymentService;
#Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}
}
The configuration is like
<bean id="custService" class="xml.CustomerServiceImpl" />
<bean id="billingService" class="xml.BillPaymentServiceImpl" />
<bean id="bankService" class="xml.BankServiceImpl">
<property name="customerService" ref="custService" />
<property name="billPaymentService" ref="billingService" />
</bean>
<bean class=”o.s.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
If we don’t set both the properties we will get an error for the BankService configuration as both are #Required.
I hope this helps!!
Same anwer by bmt - just adding here what i did to verify.
package com.requiredAnnotation;
import org.springframework.beans.factory.annotation.Required;
public class BankService {
private CustomerService customerService;
private BillPaymentService billPaymentService;
#Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}
#Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}
public BillPaymentService getBillPaymentService() {
return billPaymentService;
}
public CustomerService getCustomerService() {
return customerService;
}
}
package com.requiredAnnotation;
public class CustomerService {
}
package com.requiredAnnotation;
public class BillPaymentService {
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="customerService" class="com.requiredAnnotation.CustomerService" />
<bean id="billPaymentService" class="com.requiredAnnotation.BillPaymentService" />
<bean id="bankService" class="com.requiredAnnotation.BankService">
<property name="customerService" ref="customerService" />
<!-- <property name="billPaymentService" ref="billPaymentService" /> -->
</bean>
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
</beans>
package com.requiredAnnotation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:com/requiredAnnotation/beans-required.xml");
BankService bankService = applicationContext.getBean(BankService.class);
System.out.println("bankService got.");
System.out.println("getCustomerService - " + bankService.getCustomerService());
System.out.println("getBillPaymentService - " + bankService.getBillPaymentService());
}
}

#Qualifier Annotation in Spring is not working

I have just learnt Spring Framework and have been using Spring 2.5 for this learning. I have created three beans with these classes
Food.java
package com.spring.danipetrick;
public interface Food {
void ingredients();
}
NasiGoreng.java
package com.spring.danipetrick;
public class NasiGoreng implements Food {
public NasiGoreng() {
}
public void ingredients() {
System.out.println("Rice, Coconut oil, Egg, Crackers");
}
#Override
public String toString() {
return "Nasi Goreng";
}
}
Rendang.java
package com.spring.danipetrick;
public class Rendang implements Food {
public void ingredients() {
System.out.println("Beef, Coconut milk, spices");
}
#Override
public String toString() {
return "Rendang";
}
}
PecintaKuliner.java
package com.spring.danipetrick;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class PecintaKuliner {
#Autowired
#Qualifier("nasigoreng")
private Food food;
#Autowired
public void setFood(Food food) {
this.food = food;
}
public Food getFood() {
return this.food;
}
public void sayMaknyus() {
System.out.println(food.toString() + " memang maknyus...");
}
}
Xml configuration, qualifier-test.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="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:annotation-config />
<bean id="bondan" class="com.spring.danipetrick.PecintaKuliner">
</bean>
<bean id="rendang" class="com.spring.danipetrick.Rendang"/>
<bean id="nasigoreng" class="com.spring.danipetrick.NasiGoreng" />
</beans>
Finally, class with main method is QualifierTestMain.java:
package com.spring.danipetrick;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class QualifierTestMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/qualifier-test.xml");
PencintaKuliner bondan = (PencintaKuliner)context.getBean("bondan");
bondan.sayMaknyus();
}
}
When I run this project, I have an error like this
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.spring.danipetrick.Food] is defined: expected
single matching bean but found 2: [rendang, nasigoreng]
Why #Qualifier annotation is not working in my case?
Both your method and field are annotated with #Autowired. As such, Spring will try to inject both. On one of the runs, it will try to inject
#Autowired
#Qualifier("nasigoreng")
private Food food;
which will work because the injection target is qualified.
The method however
#Autowired
public void setFood(Food food) {
this.food = food;
}
does not qualify the injection parameter so Spring doesn't know which bean to inject.
Change the above to
#Autowired
public void setFood(#Qualifier("nasigoreng") Food food) {
this.food = food;
}
But you should decide one or the other, field or setter injection, otherwise it is redundant and may cause errors.
I tried with Spring 4.2.4. Problem resolved just by adding
<context:annotation-config /> in configuration file.
Try only removing #Autowired from setFood() in PecintaKuliner
like
#Autowired
#Qualifier("nasigoreng")
private Food food;
public void setFood(Food food) {
this.food = food;
}
Try removing you constructor from the NasiGoreng class. It worked for me.
For others facing issue in Spring 5 -- Use xmlns based configuration..
<?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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>

Categories