Togglz with Spring #Configuration bean - spring

I'm trying to implement Togglz & Spring using #Configuration beans rather than XML. I'm not sure how to configure the return type of the Configuration bean. For example:
#Configuration
public class SystemClockConfig {
#Bean
public SystemClock plainSystemClock() {
return new PlainSystemClock();
}
#Bean
public SystemClock awesomeSystemClock() {
return new AwesomeSystemClock();
}
#Bean
public FeatureProxyFactoryBean systemClock() {
FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(awesomeSystemClock());
proxyFactoryBean.setInactive(plainSystemClock());
proxyFactoryBean.setFeature(Features.AWESOME_SYSTEM_CLOCK.name());
proxyFactoryBean.setProxyType(SystemClock.class);
return proxyFactoryBean;
}
}
The systemClock method returns a FeatureProxyFactoryBean but the clients of this bean require a SystemClock. Of course, the compiler freaks over this.
I imagine it just works when XML config is used. How should I approach it when using a configuration bean?

I'm not an expert for the Java Config configuration style of Spring, but I guess your systemClock() method should return a proxy created with the FeatureProxyFactoryBean. Something like this:
#Bean
public SystemClock systemClock() {
FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(awesomeSystemClock());
proxyFactoryBean.setInactive(plainSystemClock());
proxyFactoryBean.setFeature(Features.AWESOME_SYSTEM_CLOCK.name());
proxyFactoryBean.setProxyType(SystemClock.class);
return (SystemClock) proxyFactoryBean.getObject();
}
But I'm not sure if this is the common way to use FactoryBeans with Spring Java Config.

Related

#ConfigurationProperites not binding to property source after upgrading to Spring Cloud Hoxton.SR7

I have a #ConfigurationProperties class that is no longer binding to a YML property source that gets resolved via Spring Cloud Config after upgrading to Hoxton.SR7. This code works fine using Hoxton.SR4 with the latest Spring Boot 2.2.9.RELEASE. Now, my properties are not bound and I'm receiving NPEs when I try to reference them. Following is a snapshot of my code:
#Configuration
public class MyConfiguration {
#Bean
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
In src/main/resources/META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.acme.MyConfiguration
Any ideas why my #ConfigurationProperties class doesn't bind after upgrading Spring Cloud to Hoxton.SR7?
You're mixing two ways of binding properties: class and method.
Using a method and #Bean annotation:
#Configuration
public class MyConfiguration {
#Bean
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
This will create MyPropertiesBean and store it inside the application context for you to inject.
Class level bean declaration also creates a bean for you:
#Configuration
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
This will also store a bean.
Although, you should be getting a runtime error when you try to inject MyPropertiesBean as now in your case there's two beans of the same type and Spring cannot resolve with only the type.

Switch bean by changing properties in Spring boot

I have one interface MyInterface, and 2 implementation beans: FirstImpl & SeconImpl. I want to switch between using these 2 implementations while program is running without restarting it, by only changing a property in application.properties file, e.g: interface.bean.default=FirstImpl change to interface.bean.default=SecondImpl.
Anyone knows how to do that with Spring boot?
You could try to use #ConditionalOnProperty:
#Configuration
public class MyInterfaceConfiguration {
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="firstImpl")
public MyInterface firstImpl(){
return new FirstImpl();
}
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="secondImpl")
public MyInterface secondImpl(){
return new SecondImpl();
}
}
and when you update your property in application.properties with actuator/refresh to:
my.interfacte.impl=firstImpl
you will have your FirstImpl instance. When you have:
my.interfacte.impl=secondImpl
you will have your SecondImpl.
#Hasan, your update only works if I customize it a little bit as below:
#Configuration
#RefreshScope
public class MyInterfaceConfiguration {
#Value("${my.interfacte.impl}")
String impl;
#Bean
#RefreshScope
public MyInterface getBean(){
if ("firstImpl".equals(impl)) {
return new FirstImpl();
} else if ("secondImpl".equals(impl)) {
return new SecondImpl();
}
return null;
}
}
I have to use 2 #RefreshScope at class level and bean creation method level!

How to change the implementing class when using annotations with Spring?

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 #Configuration bean created in #Bean method not enhanced by CGLIB

I'm trying to create a MainConfig that imports another Config by using an #Bean method instead of #Import like this :
#Configuration
public class MainConfig {
#Bean
public Service service() {
return new Service(infrastructureConfig().database());
}
#Bean
public OtherService otherService() {
return new OtherService(infrastructureConfig().database());
}
#Bean
public InfrastructureConfig intrastructureConfig() {
return new InfrastructureConfig();
}
}
#Configuration
public class InfrastructureConfig {
#Bean
public Database database() {
return new Database();
}
...
}
When using this technique, the Database is created twice because Spring doesn't seem to consider the #Configuration annotation on InfrastructureConfig. When using #Import, it works fine.
I don't want to use #Import because I want to mock my InfrastructureConfig like this :
#Configuration
public class TestConfig extends MainConfig {
#Override
public InfrastructureConfig infrastructureConfig() {
return mock(InfrastructureConfig.class);
}
}
Am I missing something or it is not supported ?
Thanks
When I first tried out Spring Java configuration I think I made the same assumption and was surprised when it didn't work.
I'm not sure this is the neatest way of solving this but I have used the following approach successfully.
To include that #Configuration class you can add this annotation to your MainConfig:
#ComponentScan(basePackages = "org.foo", includeFilters = {#Filter(filterType = ANNOTATION, value = CONFIGURATION)}, excludeFilters = {#Filter(filterType = ASSIGNABLE_TYPE, value = MainConfig)})
Since #Configuration classes are also candidates for component scanning this allows you to scan for all classes annotated with #Configuration. Since you're putting this annotation on MainConfig you need to exclude that with the ASSIGNABLE_TYPE filter since you'll get a circular reference.
I opened a Spring ticket SpringSource JIRA and they said that it is a known limitation and it is working as designed.

Convert Spring bean configuration into XML configuration

i am working on BIRT reporting tool. which is need to called by spring MVC.
i got one example from spring which is here. in this example, configuration is done via bean. can anyone help me convert this configuration in to xml based configuration ?
#EnableWebMvc
#ComponentScan({ "org.eclipse.birt.spring.core","org.eclipse.birt.spring.example" })
#Configuration
public class BirtWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/reports").setViewName("birtView");
}
#Bean
public BirtView birtView() {
BirtView bv = new BirtView();
// bv.setReportFormatRequestParameter("ReportFormat");
// bv.setReportNameRequestParameter("ReportName");
bv.setBirtEngine(this.engine().getObject());
return bv;
}
#Bean
public BeanNameViewResolver beanNameResolver() {
BeanNameViewResolver br = new BeanNameViewResolver();
return br;
}
#Bean
protected BirtEngineFactory engine() {
BirtEngineFactory factory = new BirtEngineFactory();
return factory;
}
}
I wants a similar configuration in xml file.
There's really no tool for extracting Spring annotations to Spring bean context xml file. You'll have to do it by hand, shouldn't be too hard as all the Spring annotations functionality can be duplicated into Spring context xml tags.
if you want to use spingmvc, so no need the configuration files.
my solution is that in Birt Script i call the impl java file like this :
sampleService = new Packages.com.example.warlock.service.SampleServiceImpl();
pojo = new Packages.com.example.warlock.entity.Sample();
iterator = sampleService.getSamples().iterator();
because my SampleService is a interface and SampleServiceImpl is impl java, the two java file are not config as #Bean.
At first i want to get the data from ModelMap but failed, so i skip the controller and straight to call Service, then final call the DAO to get the Data from DB

Resources