I want to read text data fixtures (CSV files) at the start on my application and put it in my database.
For that, I have created a PopulationService with an initialization method (#PostConstruct annotation).
I also want them to be executed in a single transaction, and hence I added #Transactional on the same method.
However, the #Transactional seems to be ignored :
The transaction is started / stopped at my low level DAO methods.
Do I need to manage the transaction manually then ?
Quote from legacy (closed) Spring forum:
In the #PostConstruct (as with the afterPropertiesSet from the InitializingBean interface) there is no way to ensure that all the post processing is already done, so (indeed) there can be no Transactions. The only way to ensure that that is working is by using a TransactionTemplate.
So if you would like something in your #PostConstruct to be executed within transaction you have to do something like this:
#Service("something")
public class Something {
#Autowired
#Qualifier("transactionManager")
protected PlatformTransactionManager txManager;
#PostConstruct
private void init(){
TransactionTemplate tmpl = new TransactionTemplate(txManager);
tmpl.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//PUT YOUR CALL TO SERVICE HERE
}
});
}
}
I think #PostConstruct only ensures the preprocessing/injection of your current class is finished. It does not mean that the initialization of the whole application context is finished.
However you can use the spring event system to receive an event when the initialization of the application context is finished:
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
See the documentation section Standard and Custom Events for more details.
As an update, from Spring 4.2 the #EventListener annotation allows a cleaner implementation:
#Service
public class InitService {
#Autowired
MyDAO myDAO;
#EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
event.getApplicationContext().getBean(InitService.class).initialize();
}
#Transactional
public void initialize() {
// use the DAO
}
}
Inject self and call through it the #Transactional method
public class AccountService {
#Autowired
private AccountService self;
#Transactional
public void resetAllAccounts(){
//...
}
#PostConstruct
private void init(){
self.resetAllAccounts();
}
}
For older Spring versions which do not support self-injection, inject BeanFactory and get self as beanFactory.getBean(AccountService.class)
EDIT
It looks like that since this solution has been posted 1.5 years ago developers are still under impression that if a method,
annotated with #Transactional, is called from a #PostContruct-annotated method invoked upon the Bean initialization, it won't be actually executed inside of Spring Transaction, and awkward (obsolete?) solutions get discussed and accepted instead of this very simple and straightforward one and the latter even gets downvoted.
The Doubting Thomases :) are welcome to check out an example Spring Boot application at GitHub which implements the described above solution.
What actually causes, IMHO, the confusion: the call to #Transactional method should be done through a proxied version of a Bean where such method is defined.
When a #Transactional method is called from another Bean, that another Bean usually injects this one and invokes its proxied (e.g. through #Autowired) version of it, and everything is fine.
When a #Transactional method is called from the same Bean directly, through usual Java call, the Spring AOP/Proxy machinery is not involved and the method is not executed inside of Transaction.
When, as in the suggested solution, a #Transactional method is called from the same Bean through self-injected proxy (self field), the situation is basically equivalent to a case 1.
#Platon Serbin's answer didn't work for me. So I kept searching and found the following answer that saved my life. :D
The answer is here No Session Hibernate in #PostConstruct, which I took the liberty to transcribe:
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
The transaction part of spring might not be initialized completely at #PostConstruct.
Use a listener to the ContextRefreshedEvent event to ensure, that transactions are available:
#Component
public class YourService
implements ApplicationListener<ContextRefreshedEvent> // <= ensure correct timing!
{
private final YourRepo repo;
public YourService (YourRepo repo) {this.repo = repo;}
#Transactional // <= ensure transaction!
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
repo.doSomethingWithinTransaction();
}
}
Using transactionOperations.execute() in #PostConstruct or in #NoTransaction method both works
#Service
public class ConfigurationService implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
private ConfigDAO dao;
private TransactionOperations transactionOperations;
#Autowired
public void setTransactionOperations(TransactionOperations transactionOperations) {
this.transactionOperations = transactionOperations;
}
#Autowired
public void setConfigurationDAO(ConfigDAO dao) {
this.dao = dao;
}
#PostConstruct
public void postConstruct() {
try { transactionOperations.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
ResultSet<Config> configs = dao.queryAll();
}
});
}
catch (Exception ex)
{
LOG.trace(ex.getMessage(), ex);
}
}
#NoTransaction
public void saveConfiguration(final Configuration configuration, final boolean applicationSpecific) {
String name = configuration.getName();
Configuration original = transactionOperations.execute((TransactionCallback<Configuration>) status ->
getConfiguration(configuration.getName(), applicationSpecific, null));
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}
I have a chain of Features. I would like to bind some beans inside ConfigFeature and then get them inside the MongoDBFeature. What methods should I use for that?
public final class IoCBinder extends AbstractBinder {
#Override
protected void configure() {
ConfigFeature.configureIoC(this);
MongoDBFeature.configureIoC(this);
}
}
Put some bean here:
public class ConfigFeature {
public static void configureIoC(AbstractBinder binder) {
// ....
binder.bind(configProvider).to(ConfigurationProvider.class).in(Singleton.class).named("configProvider");
}
}
And I would like to get configProvider bean here:
public class MongoDBFeature {
public static void configureIoC(AbstractBinder binder) {
// ?? get configProvider here ??
}
}
You can bind your bean to the ServiceLocator as shown in below example.
Service
public class TestService{
}
Binder
public static TestBinder extends AbstractBinder{
#Override
protected void configure() {
bind(new TestService()).to(TestService.class);
}
}
Feature 1
public class Feature1 implements Feature{
#Inject
private ServiceLocator locator;
#Override
public boolean configure(FeatureContext context) {
org.glassfish.hk2.utilities.ServiceLocatorUtilities.bind(locator,new TestBinder());
return true;
}
}
Note that a ServiceLocator instance is injected to Feature1 and the binder is bound to this locator instance.
Feature 2
public class Feature2 implements Feature{
#Inject
private TestService testService;
#Override
public boolean configure(FeatureContext context) {
return true;
}
}
Application/ResourceConfig class
public class TestConfig extends ResourceConfig {
register(Feature1.class);
// Need to make sure Feature1 is registered before Feature2.
// Another option is to register Feature2 in configure() method of Feature1 class.
register(Feature2.class);
}
How can i inject an EJB (3.0) in simple java class ?
When inject an EJB in my Java class, on execution i get a NullPointerException.
My Java Class test :
public class test {
#EJB MyEjb myEjb;
public test(){
myEjb.getUserbyId(2); // myEjb = null
}
}
My EJB
#Stateless
#LocalBean
public class MyEjb {
#PersistenceContext(unitName="jpa")
EntityManager EM;
public User getUserbyId(Integer id){
....
}
You should use InitialContext#lookup method to obtain EJB reference from an application server.
For example:
#Stateless(name="myEJB")
public class MyEJB {
public void ejbMethod() {
// business logic
}
}
public class TestEJB {
public static void main() {
MyEJB ejbRef = (MyEJB) new InitialContext().lookup("java:comp/env/myEJB");
ejbRef.ejbMethod();
}
}
I have a problem with #IocProvider (), annotation does not work.
The code is very similar to https://docs.jboss.org/author/display/ERRAI/Container+Wiring
public interface Test {
String getGreeting();
}
#ApplicationScoped
public class TestImpl implements Test {
public String getGreeting() {
return "Hello:)";
}
}
#IOCProvider
#Singleton
public class TestProvider implements Provider<Test> {
#Override
public Test get() {
return new TestImpl();
}
}
Then I want use DI in my broadcast service (errai-bus).
#Service
public class BroadcastService implements MessageCallback {
#Inject
Test test;
#Inject
MessageBus bus;
#Inject
public BroadcastService(MessageBus bus) {
this.bus = bus;
}
public void callback(Message message) {
MessageBuilder.createMessage()
.toSubject("BroadcastReceiver")
.with("BroadcastText", test.getGreeting()).errorsHandledBy(new ErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
return true;
}
}).sendNowWith(bus);
}
}
I get a error:
1) No implementation for com.gwtplatform.samples.basic.server.Test was bound.
while locating com.gwtplatform.samples.basic.server.Test
for field at com.gwtplatform.samples.basic.server.BroadcastService.test(BroadcastService.java:32)
at org.jboss.errai.bus.server.service.ServiceProcessor$1.configure(ServiceProcessor.java:118)
If I change the code to
#Inject
TestImpl test;
It works, but I need the provider. Do you have some idea?
Because you're trying to use #IOCProvider in server-side code. Errai IOC is completely client-side.
In my GWTP application I need to Inject HttpServletRequest, HttpSession as instance variable of ActionHandler.
My ActionHandler is initialized through Spring.
I can't get current Request object through Spring as it instantiates just POJO.
I am thinking about mixing GIN and Spring.
Would I be able inject HttpServletRequest using GIN in my ActionHandler which is instantiated through Spring?????
Is it possible to do following way??
#Configuration
#Import(DefaultModule.class)
public class ServerModule extends HandlerModule
{
#Bean
public UserVerficationActionHandler getUserVerificationActionActionHandler()
{
return new UserVerficationActionHandler();
}
}
public class UserVerficationActionHandler implements ActionHandler<UserVerficationAction, UserVerficationActionResult>
{
#Autowired
private UserService userService;
private Provider<HttpServletRequest> requestProvider;
#Inject
public UserVerficationActionHandler()
{
}
public UserVerficationActionResult execute(UserVerficationAction action, ExecutionContext context) throws ActionException
{
....
}
#Inject
public Provider<HttpServletRequest> setRequestProvider()
{
return requestProvider;
}
}
-------ActionHandler Ends--------
Can somebody let me know Is it possible to do SetterInjection this way?
Second thing, if above is possible then will I be getting current request object using this method?
Thanks in advance.
Bhavesh.