I'm trying to implement a reader java class: UserReader extends JpaPagingItemReader
this reader should execute a query String: "query_string" and return the result to the processor.
I've searched in the net and I couldn't understand how JpaPagingItemReader works?
normally I shoud find something like this:
package com.UserReader;
public class UserReader extends JpaPagingItemReader<User> {
#Override
public User read()
{
read();
}
}
<bean id="userReader"
class="com.userReader">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="queryString"
value="myQuery" />
</bean>
...step declaration reader="userReader"
But actually, I found the same java class, but with a non understable xml config (no reference to com.UserReader in spring beans but a bean with class : org.spring...jpaPagingItemReader and id: userReader), how spring batch knows that jpaPagingItemReader refers to the com.userReader class (we suppose that we can have many readers)? is it by the id of the bean?
Related
I am working on a migration project which involves upgrading the platform to Spring 4 with MyBatis. In the legacy code, transactions are handled at a central locations wherein call to start/end transactions are spread across various classes like service class, helper class and DAO class.
I managed to convert all service classes to spring managed component and DAO classes to support MyBatis-spring API. Problem is my service class use several other classes to perform a function and those classes are all instantiated manually and used. Now if i start a transaction on service class methods and perform database transactions inside other helper or DAO classes which are not spring managed, my transaction handling doesn't work correctly. I have illustrated this problem in the below code. Could you tell what are the ways to acheive transaction handling without modifying the code?
Example :
package com.service;
#Service
class MyService {
#Transactional( propagation=Propagation.REQUIRED)
public void processRequest () {
HelperClass helper = new HelperClass();
helper.performOperation();
}
}
package com.helper;
// this class is not spring bean
class HelperClass {
// MyBatis mapper class
private EmployeeMapper mapper;
public HelperClass () {
mapper = // retrieve mapper class bean from spring context
}
public performOperation () {
// call to mapper class insert operation
// call to mapper class update operation
}
}
package com.dao;
#Component
interface EmployeeMapper {
// method definition to perform database operation
}
Spring configuration details:
<context:component-scan base-package="com" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
....
....
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj" />
<mybatis:scan base-package="com.dao" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations"
value="classpath*:mybatis/*.xml" />
</bean>
In the above code HelperClass.performOperation() method is doing 2 database operations (insert,update). Say if insert succeeds and update fails, my database transaction doesn't get rollback. Since I already started the transaction at MyService.processRequest() should this not rollback the operations that are carried inside that method call? Correct me if my understanding is wrong.
I am using Guice to manager my class dependence. I have a LogicHandler class which depended on several Components class.
public interface LogicHandler {
private Component component1;
private Component component2;
private Component component3;
}
public interface Component {
public String doWork();
}
I will have 3 instances of LoigcHanlder. Using which instance will be decided in run time. Each of instance will have different Component implementation and all implementation are pre-defined.
If I were using spring DI, the xml config would be look like:
<bean id="handler1" class="org.sample.handlers.DefaultHanlder">
<property name="component1" ref="componentImplementationA" />
<property name="component2" ref="componentImplementationB" />
<property name="component3" ref="componentImplementationC" />
</bean>
<bean id="handler2" class="org.sample.handlers.DefaultHanlder">
<property name="component1" ref="componentImplementationD" />
<property name="component2" ref="componentImplementationE" />
<property name="component3" ref="componentImplementationF" />
</bean>
<bean id="handler3" class="org.sample.handlers.DefaultHanlder">
<property name="component1" ref="componentImplementationG" />
<property name="component2" ref="componentImplementationH" />
<property name="component3" ref="componentImplementationI" />
</bean>
Note: all handlers are implemented by DefaultHanlder.
Using which handler instance bases on some parameters.
Assuming I am understanding your question correctly, you would like to pick a particular concrete implementation to bind based on a particular parameter. One way to do this is to create a module that takes as a constructor the parameters you need for deciding which module to bind. The logic to bind the particular concrete implementation would be in the bind method of the module. E.g
public class YourModule extends AbstractModule {
Parameters settings;
public YourModule(Parameters settings) {
this.settings = settings;
}
#Override
protected void configure() {
if(settings.val == 1) {
bind(DefaultHanlder.class).toInstance(ComponentA.class);
} else if(settings.val == 2) {
bind(DefaultHanlder.class).toInstance(ComponentB.class);
}
.
.
.
}
When you create the injector, use the YourModule module so that the right wiring is put in place. The injector then should inject the proper concrete class for DefaultHanlder without your client code knowing how to pick the right concrete implementation.
There are probably other ways to do this as well (e.g. AssistedInjection might also work) but using a separate module is pretty straightforward.
Use Qualifiers (for example #Named("handler1")) and explicitly bind your instances.
bind(Component.class).annotatedWith(Names.named("handler1").toInstance(...);
I know there are threads similar to this issue. Below is my class and I am configuring it in spring.xml file. Actually HumanResourceService is an interface having only one method.
#Endpoint
public class HolidayEndpoint {
#Autowired
private HumanResourceService humanResourceService;
#Autowired
public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException {
this.humanResourceService = humanResourceService;
}
}
My problem is that in my spring.xml file, when I define HumanResourceService as bean, it cannot be instantiated as this is an interface. How can I mention an interface in spring configuration file. My spring.xml file is below
<bean id="holidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint" autowire="constructor" >
<property name="humanResourceService" ref="humanResourceService" />
</bean>
<bean id="humanResourceService" class="com.mycompany.hr.service.HumanResourceService" />
You can't, Spring needs something it can make an instance from, the interface isn't enough.
In your spring.xml, the value of the class attribute for your bean with id="humanResourceService" should be the name of your implementation class, not the interface. Spring needs you to tell it what implementation class you want it to use for this.
I'm trying to inject (autowire) a spring bean to an abstract class but it doesn't seem to work.
public abstract class BaseEntity {
#Autowired(required = true)
protected SecurityProvider securityService;
public BaseEntity() {
}
}
And the injected class:
#Component
public class SecurityService extends SecurityProviderImpl implements SecurityProvider {
#Autowired
public SecurityService(ICipherDescriptor cipherDescriptor) {
super(cipherDescriptor);
}
}
The SecurityService gets initialized just fine (I can see it while debugging) but the class that inherit from BaseEntity cannot use the injected SecurityService since it is null (doesn't get injected for some reason).
I tried doing it via XML as well, defining the BaseEntity as abstract:
<bean id="baseEntity" abstract="true" class="com.bs.dal.domain.BaseEntity">
<property name="securityService" ref="securityService"/>
</bean>
<bean id="securityService" class="com.bs.dal.secure.SecurityService">
<constructor-arg ref="cipherDescriptor" />
</bean>
but still with no success.
Where am I going wrong?
I think I know what's wrong here. I'm trying to inject a spring bean to an entity - which is impossible (unless you use aspectJ weaving) since the entities are not instantiated/managed by Spring. Make sense, isn't it?
If your BaseEntity is also instantiated by spring, you just need to add a parent attribute to the bean definition to link it to your BaseEntity definition like so:
<bean id="baseEntity" abstract="true" class="com.bs.dal.domain.BaseEntity">
<property name="securityService" ref="securityService"/>
</bean>
<bean id="derivedEntity" parent="baseEntity" class="com.bs.dal.domain.DerivedEntity"/>
<bean id="securityService" class="com.bs.dal.secure.SecurityService">
<constructor-arg ref="cipherDescriptor" />
</bean>
In short, the two key parts to such a definition are the abstract attribute on the parent class and the parent attribute on the subclass.
What is a good way to inject some file resource into Spring bean ?
Now i autowire ServletContext and use like below. Is more elegant way to do that in Spring MVC ?
#Controller
public class SomeController {
#Autowired
private ServletContext servletContext;
#RequestMapping("/texts")
public ModelAndView texts() {
InputStream in = servletContext.getResourceAsStream("/WEB-INF/file.txt");
// ...
}
}
Something like this:
#Controller
public class SomeController {
private Resource resource;
public void setResource(Resource resource) {
this.resource = resource;
}
#RequestMapping("/texts")
public ModelAndView texts() {
InputStream in = resource.getInputStream();
// ...
in.close();
}
}
In your bean definition:
<bean id="..." class="x.y.SomeController">
<property name="resource" value="/WEB-INF/file.txt"/>
</bean>
This will create a ServletContextResource using the /WEB-INF/file.txt path, and inject that into your controller.
Note you can't use component-scanning to detect your controller using this technique, you need an explicit bean definition.
Or just use the #Value annotation.
For single file:
#Value("classpath:conf/about.xml")
private Resource about;
For multiple files:
#Value("classpath*:conf/about.*")
private Resource[] abouts;
What do you intend to use the resource for? In you example you don't do anything with it.
From it's name, however, it looks like you are trying to load internationalisation / localisation messages - for which you can you a MessageSource.
If you define some beans (possibly in a separate messages-context.xml) similar to this:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>WEB-INF/messages/messages</value>
</list>
</property>
</bean>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en_GB" />
</bean>
Spring will load your resource bundle when you application starts. You can then autowire the MessageSource into your controller and use it to get localised messages:
#Controller
public class SomeController {
#Autowired
private MessageSource messageSource;
#RequestMapping("/texts")
public ModelAndView texts(Locale locale) {
String localisedMessage = messageSource.getMessage("my.message.key", new Object[]{}, locale)
/* do something with localised message here */
return new ModelAndView("texts");
}
}
NB. adding Locale as a parameter to your controller method will cause Spring to magically wire it in - that's all you need to do.
You can also then access the messages in your resource bundle in your JSPs using:
<spring:message code="my.message.key" />
Which is my preferred way to do it - just seems cleaner.