Using packages written by the other in Spring - java

So the package I'm trying to use is here:
https://github.com/spring-projects/spring-batch-extensions/tree/master/spring-batch-excel
and on that page is the spring bean configuration for that package. I'm new to spring, and I don't understand how to actually write code that uses the bean.
The config looks like this:
#Bean
public PoiItemReader excelReader() {
PoiItemReader reader = new PoiItemReader();
reader.setResource(new ClassPathResource("/path/to/your/excel/file"));
reader.setRowMapper(rowMapper());
return reader;
}
#Bean
public RowMapper rowMapper() {
return new PassThroughRowMapper();
}
So if I have another class called reader somewhere, how do I use this bean configuration to get the lines from the excel file that PoiItemReader gets from .setRowMapper()?
The row mapper has a list of arrays that split the values in the excel rows, but I don't know how to get that list.
Do I call the excelReader() method?
PoiItemReader doesn't have any useful methods associated with it, so I don't think I'm supposed to do that.

From your code snippet, it looks like you're using #Configuration on the class that declares your beans.
Using Java Configuration is one of the ways to define your beans so that spring will understand them and inject property at runtime.
An alternative way is using annotations like #Service, #Component, #Controller and so forth (an answer provided by maneesh)
So the first thing to understand in Spring is that there are many ways of configuration (there is also an old-way, using XML and Groovy based configuration).
Now when you write a spring application, usually you use Spring Beans from other Spring Beans.
So, if you configure bean A to have a reference on Bean B, Spring will inject it for you. Example:
public class A {
private B b;
public A(B b) {
this.b = b;
}
public void doSomething() {
b.foo();
}
}
public class B {
public void foo() {...}
}
The "java config" way for defining these beans can look like this:
#Configuration
public class MyConfiguration {
#Bean
public A a(B b) {
return new A(b);
}
#Bean
public B b() {
return new B();
}
}
In your example, you've used an alternative syntax for Configurations (line reader.setRowMapper(rowMapper());:
#Configuration
public class MyConfiguration {
#Bean
public A a() {
return new A(b());
}
#Bean
public B B() {
return new B();
}
}
It looks like from A you just call a method that creates B. But it is not quite like that, in fact, spring is supposed to wrap your configuration in some kind of runtime proxy so that, for example, if you call b() many times (for many beans), it will always return the same instance, because B has a singleton scope. All-in-all Configuration classes should be considered like a Java DSL to create beans and not a regular code.
Now the last question to consider is where all this configuration gets started. The answer to this really depends on the environment you're running it. Usually, spring is already integrated into existing projects that run on-top of tomcat or other servers, or if it's a Spring Boot application it already provides "well known" integration ways. So you might just ask someone from your project (I assume it's not a homework or something) how does your application is integrated with spring, it's beyond the scope of this question.

you should declare #Service or #Component over the class where you want to read file, and use #Autowired annotation to use PoiItemReader
#Service
public class SomeclassName {
#Autowired
private PoiItemReader excelReader;
public void somemethod() {
//do some reading stuff here using excelReader
}
}

Related

Defining a custom TransactionInterceptor in Spring. And why/how bean overridding works?

What I want to achieve
My objective is to have a transactional bean, instantiated twice (or more), and each time w/ a different TransactionManager (i.e. a different DB).
#Transactional
class MyReusableService {
...
}
#Configuration
class MyConfig {
// here I want to use `transactionManagerForDb1`
#Bean
public MyReusableService myReusableServiceForDb1() { ... }
// here I want to use `transactionManagerForDb2`
#Bean
public MyReusableService myReusableServiceForDb2() { ... }
}
What I observed
TransactionInterceptor is the piece that delegates to a TransactionManager (TM). I found it used in 2 ways:
Via #EnableJpaRepositories(... transactionManagerRef="..."). This mechanism relates a bit w/ what I want. But it doesn't use #Transactional at all. It finds all the repos. And it instantiates one TransactionInterceptor per repo.
Via #Transactional. Here, there is a single instance of TransactionInterceptor (TI). And at each invocation, it decides which TM to use by looking at the annotations (using caching of course). This TI is defined ProxyTransactionManagementConfiguration.
What I did
I defined my own TI:
#Configuration
public class MyConfiguration {
#SuppressWarnings("serial")
public static class MyTransactionInterceptor extends TransactionInterceptor {
...
}
#Bean
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new MyTransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
return interceptor;
}
}
This seem to work. The TI defined by Spring is no more instantiated. Mine is. And it is used.
My questions
Why does the above work? How did Spring know that I wanted to override it's TI? I was expecting to have 2 TIs, and fight to use the right one, maybe using #Primary. E.g. like here.
Is there maybe a cleaner way to achieve my objective? I cannot say I'm entirely satisfied, because I find the solution a bit intrusive. MyReusableService resides actually in a lib. And forcing the user to override the TI is not self contained.

Java Spring Framework. Declare classes as bean only

I am learning Java Spring in parallel with tackling a problem.
My question is:
Can I have a pool of classes defined as beans only (without them declared in the JAVA source)?
When the application runs it will do computations only on the declared classes available in the beans.
So for instance I have beans for the classes A, B ,C; But I have no declaration in the java code for this classes. I may group them together under an Interface say DocumentationVersionSpecificTag
Is this approach feasible ?
You are trying to inject objects that are not in your source code using #Autowired, you can achieve this using a configuration class, a class annotated with #Configuration, and configure these classes as beans in it, using #Bean:
#Configuration
public class ProjectConfiguration{
#Bean
public A configureA(){
return new A(); // use the suitable constructor you want
}
#Bean
public B configureB(){
return new B(); // use the suitable constructor you want
}
#Bean
public C configureC(){
return new C(); // use the suitable constructor you want
}
}
After you can inject these classes with #Autowired:
#Autowired
A a;
For more details, see this link.

Why is #Bean(initMethod="") not detecting given method in spring?

Edit Fixed by changing package.
I have this configuration file for spring framework
#Configuration
public class AppConfig {
#Bean(initMethod = "populateCache")
public AccountRepository accountRepository(){
return new JdbcAccountRepository();
}
}
JdbcAccountRepository looks like this.
#Repository
public class JdbcAccountRepository implements AccountRepository {
#Override
public Account findByAccountId(long
return new SavingAccount();
}
public void populateCache() {
System.out.println("Populating Cache");
}
public void clearCache(){
System.out.println("Clearing Cache");
}
}
I'm new to spring framework and trying to use initMethod or destroyMethod. Both of these method are showing following errors.
Caused by: org.springframework.beans.factory.support.BeanDefinitionValidationException: Could not find an init method named 'populateCache' on bean with name 'accountRepository'
Here is my main method.
public class BeanLifeCycleDemo {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new
AnnotationConfigApplicationContext(AppConfig.class);
AccountRepository bean = applicationContext.getBean(AccountRepository.class);
applicationContext.close();
}
}
Edit
I was practicing from a book and had created many packages for different chapters. Error was it was importing different JdbcAccountRepository from different package that did not have that method. I fixed it and it works now. I got hinted at this from answers.
Like you said, if you are mixing configurations types, it can be confusing. Besides, even if you created a Bean of type AccountRepository, because Spring does a lot of things at runtime, it can call your initMethod, even if the compiler couldn't.
So yes, if you have many beans with the same type, Spring can be confused an know which one to call, hence your exception.
Oh and by the way, having a Configuration creating the accountRepoisitory Bean, you can remove the #Repository from your JdbcAccountRepository... It is either #Configuration + #Bean or #Component/Repository/Service + #ComponentScan.
TL;DR
Here is more information and how Spring creates your bean : What object are injected by Spring ?
#Bean(initMethod = "populateCache")
public AccountRepository accountRepository(){
return new JdbcAccountRepository();
}
With this code, Spring will :
Detect that you want to add a Bean in the application Context
The bean information are retrieved from the method signature. In your case, it will create a bean of type AccountRepository named accountRepository... That's all Spring knows, it won't look inside your method body.
Once Spring is done analysing your classpath, or scanning the bean definitions, it will start instanciating your object.
It will therefor creates your bean accountRepository of type AccountRepository.
But Spring is "clever" and nice with us. Even if you couldn't write this code without your compiler yelling at you, Spring can still call your method.
To make sure, try writing this code :
AccountRepository accountRepository = new JdbcAccountRepository();
accountRepository.populateCache(); // Compiler error => the method is not found.
But it works for Spring... Magic.
My recommandation, but you might thinking the same now: If you have classes across many packages to answer different business case, then rely on #Configuration classes. #ComponentScan is great to kickstart your development, but reach its limit when your application grows...
You mix two different ways of spring bean declaration:
Using #Configuration classes. Spring finds all beans annotated with #Configuration and uses them as a reference to what beans should be created.
So if you follow this path of configuration - don't use #Repository on beans. Spring will detect it anyway
Using #Repository - other way around - you don't need to use #Configuration in this case. If you decide to use #Repository put #PostConstruct annotation on the method and spring will call it, in this case remove #Configuration altogether (or at least remove #Bean method that creates JdbcAccountRepository)
Annotate populateCache method with #PostConstruct and remove initMethod from #Bean. It will work.

How can I test only one bean using existing application's spring configuration class?

In my code, I don't want to load all the beans defined in the XXApplicationConfig class.
XXApplicationConfig is a #Configuration annotated file which has bunch of spring beans defined.
So, I want to load only AppBean from XXApplicationConfig class while testing to reduce loading test time and also differentiate what I am testing. I also want to load the class using XXApplicationConfig class to make sure the bean configuration defined is correct as well.
This is my Test class ( modified ) to test AppBean class.
Could you let me know if this is the right approach and suggest how to make it better? Currently, this approach seems to be working. But, not sure if it is correct way of approaching it.
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class ApplicationTest {
#Configuration
#PropertySources(value = {#PropertySource("classpath:test.properties")})
static class MyTestConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public XXApplicationConfig xxAppConfig() {
return new XXApplicationConfig();
}
#Bean
public CustomTestService customTestService() {
return new CustomTestService();
}
#Bean
public AppBean appBean() throws Exception {
return XXApplicationConfig().appBean();
}
}
#Autowired
private AppBean appBean;
#Test
public void testAppBean() {
test appBean.doSomething();
}
}
If you want to test just one object, just create one object of that class, using the constructor of that class. Spring beans are designed to be POJOs. The Spring context is just a convenient way of creating and connecting objects. Nothing stops you creating and connecting them yourself.
If you can instantiated the class you want to test and manually inject all the dependencies it required via constructor and/or setter getters, then you don't need to use Spring in your test.
However, if your bean:
uses private fields annotated with #Autowired or #Value without corresponding getters/setters.
depends on many other beans.
the behavior you want to test depends on Spring AOP/Proxies (you use #Transactional or #Cacheable for example).
Then you will need Spring to wired the bean. I personally prefer to define a a minimal #Configuration class for these cases.
Then again, if your bean meets the conditions on the list you should consider refactoring the bean to minimize its dependencies and facilitate testing.

Spring 3 Dynamically choosing bean class

So on an spring 3 app I'm building, it would be convenient to be able to read a value from configuration, and then based off of the value read, choose between two implementations of an interface and then build a bean of that object.
I have the config file setup (using util:properties), and other java code is accessing it just fine, but I'm uncertain about how to reference it in my application context xml file, and how to code this conditional logic. Or am I going about this incorrectly?
You probably want something similar to this:
#Configuration
public class MyConfiguration {
#Autowired
ApplicationContext applicationContext;
#Value("${someProperty}")
String someProperty = "B";
#Bean(name="myBean")
public MyInterface ehCacheManager() {
if ("A".equals(someProperty)) {
return new MyInterfaceA();
} else {
return new MyInterfaceB();
}
}
}
You can then differentiate by some property which interface implementation to use.

Categories