The problem started when in Spring 4.2.5 I attempted to inject an interface having more than one implementations, below is the test class :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = VenueConfig.class)
public class BandEventTest {
#Autowired
#Qualifier("rush")
Band rush;
#Autowired
Venue venue;
#Test
public void assertBandNotNull() {
Assert.assertNotNull("Who will perform if there's no band !!!", rush);
}
#Test
public void assertVenueNotNull() {
Assert.assertNotNull("Without venue, there would be no event !!!", venue);
}
#Test
public void triggerEvent() {
venue.hostPerformance();
}
}
I have the interface Band which is implemented by two beans viz. Rush and VanHalen :
#Component("rush")
public class Rush implements Band {
/*
* (non-Javadoc)
*
* #see com.book.springinaction.chap2.autowiring.Band#play()
*/
public void play() {
// TODO Auto-generated method stub
System.out.println("Rush playing 'Limelight'");
}
}
In spite of using the Qualifier annotation(please ignore the lower/upper case current Qualifier name and the Rush bean name, I have tried all the combinations in vain). My suspicion was confirmed after I read this thread about the QualifierAnnotationAutowireCandidateResolver not being set in App. context since Spring 4.0
I wish to fit the below (mentioned even in the Spring documentation) :
<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>org.springframework.beans.factory.annotation.Qualifier</value>
</set>
</property>
</bean>
in my below Configuration class WITHOUT XML i.e JUST ANNOTATIONS
#Configuration
#ComponentScan
public class VenueConfig {
/*Does using #Bean for CustomAutowireConfigurer make sense ?*/
}
I don't use Spring annotations, but your pointer to the other thread was so helpful that I did a bit of research. Based on the Spring docs, I believe you can have the same effect with:
#Configuration
#ComponentScan
public class VenueConfig {
#Bean
public CustomAutowireConfigurer qualifierAutowireConfigurer() {
CustomAutowireConfigurer customAutowireConfig = new CustomAutowireConfigurer();
customAutowireConfig.setCustomQualifierTypes( Collections.singleton( Qualifier.class ));
return customAutowireConfig;
}
}
Related
Im studying for the Spring Core cert exam, and i'm doing some testing of the framework.
I'd like to know if there is a way to know if a Bean was proxied by CGLIB or the JDK library.
I already know the basic concepts like if you declare a Bean using the interface Spring will use the JDK to proxy it (unless you tell it otherwise). And if you declare a bean directly on a class it will proxy it by inheritance using CGLIB.
What I would like to know is what should I look for while debugging to check which library was used.
Given the following code, when I debug it, I dont see any difference in the instances of the beans created. I was expecting to see something like ConcreteBean$CGLIB in the bean that has no interface...
EDIT: i now understand that proxies are only created by spring when functionality needs to be added by a PostProcessor, but still, i'd like to know what to look for in the debugger to find if CGLIB was applied or not.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MainConfig.class)
public class ProxiesTest {
#Autowired
RandomBean randomBean;
#Autowired
ConcreteBean concreteBean;
public void setUp() {
}
#Test
public void randomBeanTest() {
randomBean.doSomething();
}
#Test
public void concreteBeanTest() {
concreteBean.doSomething();
}
}
public class ConcreteBean {
public void doSomething() {
String concreteBean = "hello";
}
#PreDestroy
public void destroy() {
System.out.print("ConcreteBean Destroy");
}
}
public interface RandomBean {
public void doSomething();
public void destroy();
}
public class RandomBeanImpl implements RandomBean {
#Autowired
ApplicationContext context;
public void doSomething() {
context.getParentBeanFactory();
}
public void destroy() {
System.out.print("RandomBean destroyed");
}
}
#Configuration
#ComponentScan(basePackages = "com.certification.postprocessors")
public class MainConfig {
#Bean
public ConcreteBean concreteBean(){
return new ConcreteBean();
}
#Bean
public RandomBean randomBean() {
return new RandomBeanImpl();
}
}
When a bean is wrapped by a Spring CGLIB proxy it states $$EnhancerBySpringCGLIB.
A JDK proxy is shown as $Proxy
It looks like this in the debugging console
There have been several arguments around not using ApplicationContext.getBean() to get a bean reference, of which most are based on logic that it violates the principles of Inversion of control.
Is there a way to get reference to prototype scoped bean without calling context.getBean() ?
Consider to use Spring Boot!
Than you can do something like this...
Runner:
#SpringBootApplication
public class Runner{
public static void main(String[] args) {
SpringApplication.run(Runner.class, args);
}
}
Some Controller:
#Controller
public class MyController {
// Spring Boot injecting beans through #Autowired annotation
#Autowired
#Qualifier("CoolFeature") // Use Qualifier annotation to mark a class, if for example
// you have more than one concreate class with differant implementations of some interface.
private CoolFeature myFeature;
public void testFeature(){
myFeature.doStuff();
}
}
Some cool feature:
#Component("CoolFeature") // To identify with Qualifier
public class CoolFeature{
#Autowired
private SomeOtherBean utilityBean;
public void doStuff(){
// use utilityBean in some way
}
}
No XML files to handle.
We can still access context for manual configurations if needed.
Suggested reading:
Spring Boot Reference
Pro Spring Boot
This type of problem can be solved using method injection, which is described in more detail here: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-method-injection
This is the most common approach to create prototype bean:
abstract class MyService {
void doSome() {
OtherService otherService = getOtherService();
}
abstract OtherService getOtherService();
}
#Configuration
class Config {
#Bean
public MyService myService() {
return new MyService() {
OtherService getOtherService() {
return otherService();
}
}
}
#Bean
#Scope("prototype")
public OtherService otherService() {
return new OtherService();
}
}
I'm used to Spring with xml configuration. With xml, I can have one main implementation and one test implementation for a class, so that the test implementation will be used for JUnit tests, how can I do this with annotations ? Cause it looks like the implementation is already chosen in the "#qualifier" annotation ?
Let's take an example :
<bean id="myService" class="example.Service" />
<bean id="myHibernateDao" class="example.HibernateDao" />
<bean id="myStubDao" class="example.StubDao" />
In xml config, I can have this in src/main/resources :
<bean id="myService" class="example.Service">
<ref="myHibernateDao" />
</bean>
And this in src/test/resources :
<bean id="myService" class="example.Service">
<ref="myStubDao" />
</bean>
How can I do this with annotations, if I have already declared #Qualifier("myHibernateDao") into my service class ?
As explained in the comment above and in spring blog, you can do this via #Profile annotation.
Please find a sample config from the example below,
DataConfig.java
interface DataConfig {
DataSource dataSource();
}
StandaloneDataConfig .java
#Configuration
#Profile("dev")
public class StandaloneDataConfig implements DataConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
JndiDataConfig.java
#Configuration
#Profile("production")
public class JndiDataConfig implements DataConfig {
#Bean
public DataSource dataSource() {
try {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
} catch (NamingException ex) {
throw new RuntimeException(ex);
}
}
}
TransferServiceConfig.java
#Configuration
public class TransferServiceConfig {
#Autowired
DataConfig dataConfig;
#Bean
public TransferService transferService() {
return new DefaultTransferService(accountRepository(), feePolicy());
}
#Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataConfig.dataSource());
}
#Bean
public FeePolicy feePolicy() {
return new ZeroFeePolicy();
}
}
Setting bean profile to an application context
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setDefaultProfiles("dev");
ctx.register(TransferServiceConfig.class, StandaloneDataConfig.class,
JndiDataConfig.class);
ctx.refresh();
Since the bean profile has been set to Dev, The TransferServiceConfigwill be injected with StandaloneDataConfig
You can basically do the same thing with #Configuration classes.
Production Setup
Let's assume you have many different DAO implementations that might or might not implement a common interface (it doesn't matter). Let's further assume that MyServiceDao is the concrete implementation that your Service class needs.
Write the following configuration classes:
#Configuration
public class MyServiceConfiguration {
#Bean
public Service myService(MyServiceDao dao) {
return new Service(dao);
}
}
-
#Configuration
public class MyProductionServiceDaoConfiguration {
#Bean
public MyServiceDao myServiceDao() {
return new MyServiceDao();
}
}
Methods in #Configuration classes that are annotated with #Bean are eligible for Spring's auto-wiring. In the MyServiceConfiguration above, Spring will use the type of the method parameter to find a matching bean. If you include MyProductionServiceDaoConfiguration when creating the Spring context, this will be the instance of MyServiceDao that myServiceDao() created.
Test Setup
In your tests, you want to replace MyServiceDao with a stub. The stub needs to extend MyServiceDao so that Spring can find the right bean based on types. Let's call the stub MyServiceDaoStub. Whether you create it using a library like Mockito (which can also create stubs, not just mocks) or actually write an extension of MyServiceDao is up to you.
Instead of including MyProductionServiceDaoConfiguration in your Spring configuration, use the following class:
#Configuration
public class MyTestServiceDaoConfiguration {
#Bean
public MyServiceDao myServiceDao() {
return new MyServiceDaoStub();
}
}
In your test use #ContextConfiguration to load the test setup:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyServiceConfiguration.class, MyTestServiceDaoConfiguration.classs })
public class MyServiceTest {
// your tests
}
Using #Autowired
Spring will also process #Autowired annotations in objects returned from #Bean annotated methods. If your Service looks like this:
public class Service {
#Autowired
private MyServiceDao dao;
// more code
}
you can change the myService() method to:
#Bean
public Service myService() {
return new Service();
}
Spring is failing to autowire my object? Is it possible to autowire an object within an abstract class. Assume all schemas are supplied in application-context.xml
Question: What annotation should be on the base and extending classes (if any) #Service #Component?
Example
abstract class SuperMan {
#Autowire
private DatabaseService databaseService;
abstract void Fly();
protected void doSuperPowerAction(Thing thing) {
//busy code
databaseService.save(thing);
}
}
Extending class
public class SuperGirl extends SuperMan {
#Override
public void Fly() {
//busy code
}
public doSomethingSuperGirlDoes() {
//busy code
doSuperPowerAction(thing)
}
application-context.xml
<context:component-scan base-package="com.baseLocation" />
<context:annotation-config/>
I have that kind of spring setup working
an abstract class with an autowired field
public abstract class AbstractJobRoute extends RouteBuilder {
#Autowired
private GlobalSettingsService settingsService;
and several children defined with #Component annotation.
Normally, Spring should do the autowiring, as long as your abstract class is in the base-package provided for component scan.
See this and this for further reference.
#Service and #Component are both stereotypes that creates beans of the annotated type inside the Spring container. As Spring Docs state,
This annotation serves as a specialization of #Component, allowing for
implementation classes to be autodetected through classpath scanning.
What if you need any database operation in SuperGirl you would inject it again into SuperGirl.
I think the main idea is using the same object reference in different classes.
So what about this:
//There is no annotation about Spring in the abstract part.
abstract class SuperMan {
private final DatabaseService databaseService;
public SuperMan(DatabaseService databaseService) {
this.databaseService = databaseService;
}
abstract void Fly();
protected void doSuperPowerAction(Thing thing) {
//busy code
databaseService.save(thing);
}
}
#Component
public class SuperGirl extends SuperMan {
private final DatabaseService databaseService;
#Autowired
public SuperGirl (DatabaseService databaseService) {
super(databaseService);
this.databaseService = databaseService;
}
#Override
public void Fly() {
//busy code
}
public doSomethingSuperGirlDoes() {
//busy code
doSuperPowerAction(thing)
}
In my opinion, inject once run everywhere :)
In my case, inside a Spring4 Application, i had to use a classic Abstract Factory Pattern(for which i took the idea from - http://java-design-patterns.com/patterns/abstract-factory/) to create instances each and every time there was a operation to be done.So my code was to be designed like:
public abstract class EO {
#Autowired
protected SmsNotificationService smsNotificationService;
#Autowired
protected SendEmailService sendEmailService;
...
protected abstract void executeOperation(GenericMessage gMessage);
}
public final class OperationsExecutor {
public enum OperationsType {
ENROLL, CAMPAIGN
}
private OperationsExecutor() {
}
public static Object delegateOperation(OperationsType type, Object obj)
{
switch(type) {
case ENROLL:
if (obj == null) {
return new EnrollOperation();
}
return EnrollOperation.validateRequestParams(obj);
case CAMPAIGN:
if (obj == null) {
return new CampaignOperation();
}
return CampaignOperation.validateRequestParams(obj);
default:
throw new IllegalArgumentException("OperationsType not supported.");
}
}
}
#Configurable(dependencyCheck = true)
public class CampaignOperation extends EO {
#Override
public void executeOperation(GenericMessage genericMessage) {
LOGGER.info("This is CAMPAIGN Operation: " + genericMessage);
}
}
Initially to inject the dependencies in the abstract class I tried all stereotype annotations like #Component, #Service etc but even though Spring context file had ComponentScanning for the entire package, but somehow while creating instances of Subclasses like CampaignOperation, the Super Abstract class EO was having null for its properties as spring was unable to recognize and inject its dependencies.After much trial and error I used this **#Configurable(dependencyCheck = true)** annotation and finally Spring was able to inject the dependencies and I was able to use the properties in the subclass without cluttering them with too many properties.
<context:annotation-config />
<context:component-scan base-package="com.xyz" />
I also tried these other references to find a solution:
http://www.captaindebug.com/2011/06/implementing-springs-factorybean.html#.WqF5pJPwaAN
http://forum.spring.io/forum/spring-projects/container/46815-problem-with-autowired-in-abstract-class
https://github.com/cavallefano/Abstract-Factory-Pattern-Spring-Annotation
http://www.jcombat.com/spring/factory-implementation-using-servicelocatorfactorybean-in-spring
https://www.madbit.org/blog/programming/1074/1074/#sthash.XEJXdIR5.dpbs
Using abstract factory with Spring framework
Spring Autowiring not working for Abstract classes
Inject spring dependency in abstract super class
Spring and Abstract class - injecting properties in abstract classes
Spring autowire dependency defined in an abstract class
Please try using **#Configurable(dependencyCheck = true)** and update this post, I might try helping you if you face any problems.
I have been trying to use autowiring, but it fails to get autowired. Here is the code snippet,
App context file:
<context:annotation-config />
<context:component-scan base-package="com.shapes" />
<bean id = "triangle" class = "com.shapes.Triangle" autowire="byName"></bean>
Triangle class:
#Component
public class Triangle implements Shape {
#Override
public void draw() {
System.out.println("In draw");
}
}
Main class :
public class MainShapes {
#Autowired
private Triangle triangle;
/**
* #param args
*/
public static void main(String[] args) {
MainShapes shapes = new MainShapes();
shapes.triangle.draw();
}
}
Only spring-managed beans will get autowired automatically (unless you use some kind of AOP).
In your main class you create MainShapes manually, and there is nothing related to spring except annotations.
It won't magically work that way. You probably want to retrieve your MainShapes from spring ioc container (and make sure that it is in app context) ...