I've been using the #Required annotation up to now to ensure DI of my beans in a Spring configured application.
To enable the annotation, you need to declare a RequiredAnnotationBeanPostProcessor bean in your configuration.
In your test configuration you just don't declare it, so that if some beans are not needed you don't have to have them in your config.
I want to switch to less XML and use #Autowired annotation, but it is by default required=true, which is fine for the runtime configuration.
But I need #Autowired to be required=false for testing purpose only - while keeping it required for runtime.
Is that possible at all? I can't find a way to declaratively turn the required property to false.
cheers
You probably solved it already but this trick might be useful for others.
As far as I understood without context:annotation-driven being present #Autowired annotations should not be processed but this is clearly not the case so I might misunderstood something.
However, I needed a quick solution... This somewhat dirty trick negates required value for all classes making optional what was required before. Adding it to my test context solved my problem but it is useful only if all autowirings are required in your business classes.
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="requiredParameterValue" value="false" />
</bean>
I worked out a solution that works for JavaConfig configurations
#ContextConfiguration(initializers={DisableAutowireRequireInitializer.class})
public class TestCase {
// Some tests
}
public class DisableAutowireRequireInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Register the AutowiredAnnotationBeanPostProcessor while initalizing
// the context so we get there before any #Autowire resolution happens
// We set the "requiredParameterValue" so that #Autowire fields are not
// required to be resolved. Very useful for a test context
GenericApplicationContext ctx = (GenericApplicationContext) applicationContext;
ctx.registerBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
BeanDefinitionBuilder
.rootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class)
.addPropertyValue("requiredParameterValue", false)
.getBeanDefinition());
}
}
You can use the same technique as you did with #Required - don't register the AutowiredAnnotationBeanPostProcessor in your test context, but leave it in your live context.
This is usually registered by adding <context:annotation-driven/>, rather than being declared manually.
Related
I have a collection of classes which I want to be injected into the Spring application context. However, these classes can only be guaranteed to be annotated with one of a group of annotations I have written - i.e. I can assume it will be annotated with #MyAnnotation, but not #Component.
However, #MyAnnotation forms part of an API for my project, and I don't want to state an explicit dependency of this API on Spring. Thus, I can't annotate #MyAnnotation with #Component in order to have it be transitively picked up by Spring.
Is there a way to tell Spring to additionally include #MyAnnotation in its classpath scanning without adding this dependency to my API?
Currently I'm manipulating the bean definition registry to 'manually' add each class annotated with #MyAnnotation, but I'd prefer to rely on Spring's inbuilt support.
Thanks in advance.
It's possible if you create your own BeanDefinitionRegistryPostProcessor to register your own beans. If you implement the postProcessBeanDefinitionRegistry method, you can add beans to the registry by yourself, for example:
#Component
public class FooFactoryBean implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition(..);
}
}
To obtain these bean definitions, you can use the ClassPathScanningCandidateComponentProvider class, which will create BeanDefinition objects for all classes found for a specific filter. In this case, an AnnotationTypeFilter will work:
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Foo.class));
Set<BeanDefinition> definitions = scanner.findCandidateComponents("com.example.my");
In this example, it will find all classes annotated with #Foo in the com.example.my package.
#Configuration classes and XML based configuration should work for you. Have a look at this tutorial: https://www.tutorialspoint.com/spring/spring_java_based_configuration.htm
But to get your #MyAnnotations picked up is more difficult (see #g00glen00b's answer), and I'm not sure it makes sense if the above mentioned solutions are available.
When I setup Spring with XML a can override component definitions in XML files that are loaded later.
It's very usefull for tests - I create default config set and than load it with addition test configuration that replaces some of components with specials (stubs, mocks, and so on).
Now i start to migrate to annotation based configurations and it causes some problems.
The direct way to use annotations is auto-discovering of packages with #Component
So I have
#Configuration
#ComponentScan({"some.pack1", "some.pack2"})
public class ProductConfig{}
And when
#Configuration
#Import({ProductConfig.class})
#ComponentScan({"test.pack"})
public class TestConfig{}
But it will cause conflict if I try to override components in test.pack
And what I can do?
After some investigations where are 3 answers with some issues on them
Worst - i can use #Filter on ComponentScan - it's worst way,
i must not import existed config (that can has some additional beans)
i must rescan all components, and explicitly define set of filters
i can use #Profile and activeProfiles - it's better, while it's more sophistical, implict, but
it means that i must to know at product classes that they can be disabled in some tests
not to use #ComponentScan on override Config and using #Bean insted of it
it's maybe well on test configurations, but it means that I lost ability to use #Component annotation
use setParent on contexts - it works well, but
it's explicit operation on implementation of ApplicationContext not on interface
it's not hard to setup if overriding services has #Autwire dependency on some components from overriden config - require manual register and refresh
What is best and standard way to override conigurations??? When I used XML-based it was not a problem...
#profile plays a crucial role while implementing the testing strategy for your service/code.
For example, in development, you may have:
public interface DataSource{
public String getHost();
}
Default implementation is
#Component
#Profile("Prod")
public class DevDataSource implements DataSource {
public String getHost(){
// return actual value
}
And the implementation for component tests(Fake impl)
#Component
#Profile("test")
public class StubbyDataSource implements DataSource {
public String getHost(){
return "some-host"; // return mocked data
}
Now you can write a test here which can act as integration test, unit test and component tests (https://martinfowler.com/bliki/ComponentTest.html)
In that way, your testing strategy would be much more elegant, concise and easy to maintain. Just by changing the profile, the same test can point to different environments (real or fake).
I'm pretty new to the Spring Framework and I got problems to understand the #Required annotation in combination with a Java configured application.
Here is an example.
Config-File
#Configuration
public class AppConfig {
#Bean
public Movie movieA() {
return new Movie();
}
#Bean
public MovieHolder holder() {
return new MovieHolder();
}
}
MovieHolder.java
public class MovieHolder {
private Movie movie;
public Movie getMovie() {
return movie;
}
#Required
public void setMovie(Movie movie) {
this.movie = movie;
}
}
Context initialization
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MovieHolder holder = (MovieHolder) context.getBean("holder");
System.out.println("movie: " + holder.getMovie());
As far as I understood the documentation of the #Required annotation, there should rise an exception, because movie isn't set directly or by autowiring. Instead is the output movie: null.
What am I doing wrong? Or isn't this the correct use of the #Required annotation?
Setting the required properties in the beans that you are instantiating is your own responsibility. The BeanPostProcessor that processes the bean-definitions in the classes annotated with #Configuration is called ConfigurationClassPostProcessor. The BeanPostProcessor that processes your #Required annotation defaults to RequiredAnnotationBeanPostProcessor, which is registered by default when you use context:annotation-config and context:component-scan in your configuration. If you are not using these two tags, you can even register your own RequiredAnnotationBeanPostProcessor as a bean.
Now, the default implementation of the RequiredAnnotationBeanPostProcessor has a method called boolean shouldSkip(..) that checks for a boolean attribute named SKIP_REQUIRED_CHECK_ATTRIBUTE. The value of this attribute is checked for each bean during the post-processing by the RequiredAnnotationBeanPostProcessor. If it returns false, the #Required constraint is enforced, otherwise it is not.
Now, the ConfigurationClassPostProcessor set the value of this attribute to true while creating the bean definitions from the #Configuration classes (I guess for the reason that if you are defining a bean, you should ensure that it has the required properties). Hence, the #Required is not enforced for such beans.
As an aside, You might think that where did this SKIP_REQUIRED_CHECK_ATTRIBUTE attribute come from and where is it set: it is set on the instances of BeanDefinition that are used by Spring internally for bean creation and post-processing.
If you really want to enforce the #Required constraints, you would have to override the RequiredAnnotationBeanPostProcessor, override the boolean shouldSkip(..) method and register this class instead of the default RequiredAnnotationBeanPostProcessor. And as the documentation for RequiredAnnotationBeanPostProcessor says:
A default RequiredAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags. Remove or turn off the default annotation configuration there if you intend to specify a custom RequiredAnnotationBeanPostProcessor bean definition.
Another way would be to use the initMethod attribute on your #Bean annotation. Which could perform checks to see that the required properties are indeed set. However, since this is code based configuration, you could just as well call that init method yourself.
Also, in my opinion, there is not much point in going through a lot of trouble to use your own RequiredAnnotationBeanPostProcessor, as the following documentation says:
Please note that an 'init' method may still need to implemented (and may still be desirable), because all that this class does is enforce that a 'required' property has actually been configured with a value. It does not check anything else... In particular, it does not check that a configured value is not null.
So, to summarize: #Required doesn't work with #Configuration classes by default. If you need to make sure that all your properties are set, you can just as well do it yourself when you create the bean in the #Bean methods (By calling some init method that performs such validations, or just supplying the required properties yourself). And if you really need to make the #Required annotation work, you'd need to use your own implementation of the RequiredAnnotationBeanPostProcessor, register it as a bean in the spring context and give up the benefits of context:annotation-config.
Just tried to declare a #Bean RequiredAnnotationBeanPostProcessor with overridden shouldSkip() method.
Yes, it checks my beans, but it fails even if I set all the required properties, i.e. it always fails.
I think Spring has a real problem with supporting #Required annotation for Java Config, since Spring has no way to tell whether or not you have set the property when you do it directly in Java code. (It can't inspect for 'null' fields later, since this would mean changing the semantics of the #Required annotation which should allow explicitly set null values).
When you use an XML config, Spring creates a wrapper object to set the properties, so it can track all the configured 'setXxx()' operations.
Conclusion: there is no reasonable way to enable #Required annotation for beans created in Java #Configuration classes.
(Very unfortunate feature, in my opinion, since the bean class writer and the class user might be different persons).
In a modular Spring configured application, we use factory beans to provide bean instances across module boundaries.
For example, one module A may expose a bean instance by the name name. Another module B can then consume that bean via a declaration of the style
<bean id="nameBean" class="com.zfabrik.springframework.ComponentFactoryBean">
<property name="componentName" value="A/name" />
<property name="className" value="a.AInterface" />
</bean>
Note that modules have separated class loader hierarchies and the actual implementation class of A/name may not be visible in B. As if in OSGI (although this is NOT OSGi).
My goal is to provide A/name in a programmatic application context in B. However when trying
#Configuration
public static class AppContext {
#Bean AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
(lookup does the actual instance retrieval) I see that Spring is trying to configure the returned instance. For example, it will attempt to resolve #Autowired properties of A/names's implementation class - which does not make sense in the context of B (and the deal of the lookup is to provide something fully configured anyway). Even, if I try
#Configuration
public static class AppContext {
#Bean(autowire=Autowire.NO) AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
it will go about configuring the returned instance.
How can I provide a bean to the application context without spring touching its implementation instance?
EDIT: As suggested by Sotirios Delimanolis, returning the FactoryBean does AFAICT avoids Spring configuration of the returned instance.
The alternative code would look like this:
#Configuration
public static class AppContext {
#Bean FactoryBean<AInterface> nameBean() {
return new ComponentFactoryBean("A/name",AInterface.class);
}
}
It's not as cool as an #UntouchedBean annotation because of the FactoryBean in the return type, but it solves the problem.
#Sotirios: Please suggest as answer so that I can tag your suggestion accordingly.
/EDIT
Ok, just so it can be closed. The suggested and accepted answer is to return the factory bean.
It seems not the case. I used to have the notion that XML configurations are meant to override annotations. But when I set autowire="no" in the XML configuration, the bean's #Autowired annotated property still takes effect. I'm no longer sure if XML autowire has anything to do with #Autowired anymore. It's quite counter-intuitive in my opinion.
Can someone point me to a documentation that says something about this?
Here's my example:
<bean class="com.example.Tester"></bean>
<bean class="com.example.ClassToTest" autowire="no"></bean>
public class Tester
{
#Autowired
ClassToTest testSubject;
}
public class ClassToTest
{
#Autowired // I want this not to get autowired without removing this annotation
private OtherDependency;
}
autowire="no" means we have to explicit wire our dependencies using either XML-based configuration or #Autowire and it is default setting.
Auto-wiring by xml configutaion or by annotation means implicitly mapping dependencies using given strategy.
For more details refer here