We have a Spring-based Java library. There is a code like this:
#Configuration
public class MyConfig {
#Bean
public MyClass createMyClass(#Autowired ObjectMapper objectMapper) {
...
}
}
The code is supposed to be used only as a library, as part of a full Spring Boot application. In that application, there is ensured that an ObjectMapper bean always exists.
Maven build ends up with BUILD SUCCESS. However, IntelliJ IDEA complains:
Could not autowire. No beans of 'ObjectMapper' type found.
What is the correct way of solving the issue?
Is there an annotation parameter something like #Autowired(provided=true) telling the IntelliJ that the bean will be provided in the full program?
Is it OK just to ignore / suppress (and how?) this IntelliJ error, secretly knowing that it will be eventually OK?
Or is it a bad practice and such code should be avoided and replaced by another construct?
EDIT:
As a solution I tried to add to the library a "fake" bean like this:
#Bean
#OnMissingBean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
This made IDEA happy, however as Spring Boot creates the bean also with #OnMissingBean annotation (or maybe it wasn't ObjectMapper but some other class, it doesn't matter now), I never knew which bean takes precedence and it happened that this fake bean was used.
Related
I have below working groovy code from Spring framework project:
import org.springframework.oxm.Unmarshaller
public class ItemSearchService {
Unmarshaller unmarshaller;
public ItemSearchResponse getObject(InputStream xml) {
ItemSearchResponse its = null;
try {
its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
} finally {
}
return its;
}
}
Unmarshaller.unmarshall is actually interface method:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Unmarshaller.html
Unmarshaller interface is implemented by several classes.
Who decides which implementing class to inject during runtime and how it decides which class to use?
Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?
Also how to know which implementing class it actually used?
Will above code work outside of Spring in ordinary Java file assuming dependent jars in classpath?
As soon as it goes about a Grails project (not a pure Spring one), some things should be clarified.
Who decides which implementing class to inject during runtime and how it decides which class to use? Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?
What Spring does in a plain Spring(Boot) is nicely described by #svr s answer and other documentation on the Internet, but has not much to do with your case.
In Grails the convention-over-configuration doctrine is used, meaning that
by default Bean Autowiring is active
only beans which are declared as Grails artefacts, like Service are auto-injected.
Usually, if you want to autowire a bean of other stereotype, you have to declare it somewhere, otherwise Spring IoC container inside Grails simply won't find it.
You shall check your grails-app/conf/spring folder for resources.groovy (or maybe yaml or xml files depending on version ) and see if your unmarshaller bean is defined there. It should look like:
beans = {
unmarshaller Unmarshaller ....
}
So, basically it doesn't matter how many implementations of Unmarshaller interface are present in all project's jar files. The only thing what matters is what defined in your resources.groovy.
If you want to check the class of the bean in runtime, just log it's class in your service:
class ItemSearchService {
Unmarshaller unmarshaller
ItemSearchResponse getObject(InputStream xml) {
log.info "unmarshaller's class is $unmarshaller.class"
// or
// println "unmarshaller's class is $unmarshaller.class"
}
}
Who decides which implementing class to inject during runtime and how
it decides which class to use?
Does Spring IoC mechanism does this? If so does it pick up one
specific implementing class during build time when jar is generated or
it does it during run time?
Yes Spring IOC container. It happens at run time when the application is run.
Also how to know which implementing class it actually used?
For most part you will have to define bean with implementation to pick. For other cases you can look at the spring auto configuration classes.
Will above code work outside of Spring in ordinary Java file assuming
dependent jars in classpath?
Not sure what you mean outside of Spring but as long as application is packaged correctly it should all work.
Quick Overview
Spring IOC will only inject a bean when found in the application context. An application context loosely is repository of beans.
Classpath Scanning and Registration
Spring scans application to pick up all the stereotyped classes and registers bean definition with application context. Stereotyped annotations include #Component, #Repository, #Service, #Controller, #Configuration. More
Dependency Injection
Spring DI creates the bean and injects them as dependencies into application. You can create dependencies between different application components using the registered beans and spring will autowire these for you. More. There are two types of DI - Constructor based and setter based - Constructor for required dependencies and setter based for optional dependencies. More
There are sensible defaults provided when you use any spring classes. You just have to define the bean where there is no default or you would like to pick different implementation. Application context can be further be enriched by using Spring Boot Auto Configuration where all related classes are wired together to form a coherent entry classes. You can then easily inject these into application for getting started. More
Example
You can define bean in the #Configuration class for a web service module.
#Configuration
public class WSConfig {
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marsharller = new Jaxb2Marshaller();
marsharller.setContextPath("some package");
}
#Bean
public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marsharller) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marsharller);
}
}
#RequiredArgsConstructur
public class ItemSearchService {
private final Unmarshaller unmarshaller;
public ItemSearchResponse getObject(InputStream xml) {
ItemSearchResponse its = null;
try {
its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
} finally {}
return its;
}
}
This similar configuration is automatically taken care by WebServicesAutoConfiguration with ways to customize when using Spring Boot.
I have a multi-datasource web application with following technique:
Spring boot 1.5.12
Mybats-Spring-boot-starter 1.3.2
And I prefered Java based configuration. Therefore, I have Datasource1Config.java and Datasource2Config.java.
I defined SqlSessionTemplate respectively, and using MapperScannerConfigure to inject my mapper. Following is for datasource1, and the datasource2 just substitute the number.
#Bean(name = "dataSource1MapperScannerConfigurer")
public MapperScannerConfigurer msc() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setSqlSessionFactoryBeanName("dataSource1SqlSessionFactory");
msc.setSqlSessionTemplateBeanName("dataSource1SqlSessionFactory");
msc.setBasePackage("demo.mybatisspring.mapper.ds1");
return msc;
}
And then, the error happend
file [C:\...target\classes\demo\mybatisspring\mapper\ds1\UserMapper.class] required a single bean, but 2 were found:
- dataSource1SqlSessionFactory: defined by method 'sqlSessionFactoryBean' in class path resource [demo/mybatisspring/config/DataSource1Config.class]
- dataSource2SqlSessionFactory: defined by method 'sqlSessionFactoryBean2' in class path resource [demo/mybatisspring/config/DataSource2Config.class]
However, if I inject mappers with #MapperScan as following, everything will work fine. (also worked fine when one using #MapperScan and the other using #Bean MapperScannerConfigurer)
#MapperScan(basePackages = "demo.mybatisspring.mapper.ds1", sqlSessionTemplateRef = "dataSource1SqlSessionFactory")
public class DataSource1Config {...}
#MapperScan(basePackages = "demo.mybatisspring.mapper.ds2", sqlSessionTemplateRef = "dataSource2SqlSessionFactory")
public class DataSource2Config {...}
I've tried to trace with debug mode and search so many articles on internet, still can not get the answer instead. So if anyone can help me?
Thanks for your time.
I think answer is here. https://mybatis.org/spring/mappers.html
Scanning for mappers There is no need to register all your mappers one
by one. Instead, you can let MyBatis-Spring scan your classpath for
them.
There are three different ways to do it:
Using the element. Using the annotation #MapperScan
Using a classic Spring xml file and registering the
MapperScannerConfigurer Both and #MapperScan are
features introduced in MyBatis-Spring 1.2.0. #MapperScan requires
Spring 3.1+.
Since 2.0.2, mapper scanning feature support a option
(lazy-initialization) that control lazy initialization
enabled/disabled of mapper bean. The motivation for adding this option
is supporting a lazy initialization control feature supported by
Spring Boot 2.2. The default of this option is false (= not use lazy
initialization). If developer want to use lazy initialization for
mapper bean, it should be set to the true expressly.
I liked annotations used for bean declaration etc. But now we have so many beans with order (#Depends). It is tough to maintain or look at a glance the configuration.
Is there any tool that provides "Effective Spring Config" information based on all your bean annotations?
Answer: you should not be using that many #DependsOn annotations.
From the javadoc:
Used infrequently in cases where a bean
does not explicitly depend on another through properties or
constructor arguments, but rather depends on the side effects of
another bean's initialization.
You can just do this:
#Configuration
public class MyConfig {
#Bean
public MovieClient movieClient(RestOperations rest) {
return new MovieClientImpl(rest);
}
#Bean
public RestOperations restOps() {
return new RestTemplate();
}
}
In this example, the RestOperations bean will be instantiaded before the MovieClient bean, just because the movieClient bean asks for it in the constructor. You don't need any #DependsOn annotion in cases like this one.
Edit: as OP commented, there is still the issue of showing the "Effective Spring Config".
I do not think there is any tool for that, because your dependencies may change at runtime (because of AutoConfiguration, #Conditional annotations, profiles, other?).
If you need to know your "Effective Spring Config" (i.e. "what beans are present at runtime"), you can do this:
ConfigurableApplicationContest context;
context = SpringApplication.run(Application.class, finalArgs);
// Print all the beans:
System.out.println(context.getBeanDefinitionNames());
However, if you meant how can you view and navigate all the configuration, you can organize your beans in different #Configuration files, pick them up using #ComponentScan, and navigate them using the Spring IDE pluguin for Eclipse, like this:
I'm a little bit lost in Spring's Property Replacement mechanism. Lets say I have this Java Config
#Configuration
#ComponentScan(basePackageClasses = Application.class)
#PropertySources({
#PropertySource("classpath:/config/default.properties")
})
public class ApplicationConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
return pspc;
}
Now I want to add a Spring-Data Annotation #EnableMongoRepositories and define a custom basepackage for scanning, using a custom placeholder like follows
#EnableMongoRepositories("${my.custom.repobasepackage}"). The Placeholder is defined in my default.properties.
However, this property cannot be resolved here. When diving deeper into Spring's property replacement, I can see that it tries to resolve the property, so it is possible to do so.
However, the underlying Environment class which is used to replace the placeholder does not know about my PropertyPlaceholderConfigurer, but only know about my SystemProperties and my VM-Props. :-(
I can see that in org.springframework.context.annotation.ClassPathBeanDefinitionScanner#getOrCreateEnvironment.java#339 (I'm using Spring 4.0.1) my "PropertyPlaceholder" is already in place, so its not a question of ordering in initialization, but is not used, because the used BeanDefinitionRegistry does not implement the Interface EnvironmentCapable. Here, my understanding of the Spring App-Context Bootstrapping is at the end.
Can anybody help me out here? Is there a BeanDefinitionRegistry out there which is capable of providing the Environment Instance which uses my Property Placeholder?
Any help is highly appreciated!! I got cookies for you! :-))
Cheers, Stefan
I imagine that the #PropertySources (you only have one by the way so you don't need the wrapper) are added to the Environment after the config classes are processed, so it will be too late to resolve on one of the annotations of those classes themselves. You can verify this by setting my.custom.repobasepackage as a System property.
As an alternative I encourage you to try out Spring Boot (where application.properties is added to the Environment before any configuration is processed).
I'm writing a web app with Java & Spring 2.5.6 and using annotations for bean validation. I can get the basic annotation validation working fine, and Spring will even call a custom Validator declared with #Validator on the target bean. But it always instantiates a brand new Validator object to do it. This is bad because the new validator has none of the injected dependencies it needs to run, and so it throws a null pointer exception on validate. I need one of two things and I don't know how to do either.
Convince Spring to use the validator I have already configured.
Convince Spring to honor the #Autowired annotations when it creates the new validator.
The validator has the #Component annotation, like this.
#Component
public class AccessCodeBeanValidator implements Validator {
#Autowired
private MessageSource messageSource;
Spring finds the validator in the component scan, injects the autowired dependencies, but then ignores it and creates a new one at validation time.
The only thing that I can do at the moment is add a validator reference into the controller for each validator object and use that ref directly, instead of relying on the bean validation framework to call the validator for me. It looks like this.
// first validate via the annotations on the bean
beanValidator.validate(accessCodeBean, result);
// then validate using the specific validator class
acbValidator.validate(accessCodeBean, result);
if (result.hasErrors()) {
If anyone knows how to convince spring to use the existing validator, instead of creating a new one, or how to make it do the autowiring when it creates a new one, I'd love to know.
Edit:
Here is the code that tells spring what validator to use for the bean.
#Validator(AccessCodeBeanValidator.class)
public class AccessCodeBean {
It works, but is limited as described above.
And so, currently, I have the #Validator line commented out and instead I'm autowiring the validator to the controller like this.
#Resource(name="accessCodeBeanValidator")
public void setAcbValidator(Validator acbValidator) {
this.acbValidator = acbValidator;
}