guice JpaPersistModule with runtime configuration - jpa

I need to share datasource with JpaPersistModule. This datasource is provided by guice injector.
Now the problem I have to build module during configuration phase, but datasource is available only in runtime.
Currently I have following code:
public class MyJpaConfigurationModule implements Module {
private Map<String, Object> jpaProperties = new HashMap<>();
private Module jpaModule = new JpaPersistModule("peristenceUnit").properties(jpaProperties);
public void configure(Binder binder) {
binder.requestInjection(this);
binder.install(jpaModule);
}
#Provides #Singleton
public DataSource provideDatasource() {
return ..... // some data source
}
#Inject
public void setJpaProperties(DataSource dataSource, PersistService persistService) {
jpaProperties.put("dataSource", dataSource);
persistService.start();
}
}
I have checked and it seems that jpa properties map is everywhere injected by reference, so my runtime changes should become visible, but what if this changes in future?
What is the correct way to resolve such conflicts?

Related

Spring Boot Hibernate Postgresql #Transactional does not rollback [duplicate]

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 {
}
}

microprofile-config custom ConfigSource using JPA

I am currently trying to setup a custom ConfigSource reading config values from our DB2. As the ConfigSources are loaded via ServiceLoader it looks like there is no way to access the database via JPA as the ServiceLoader is scanning for custom ConfigSources very early.
Any ideas?
You can anotate your ConfigSource as a singleton session bean and mark it for eager initialization during the application startup sequence.
Also you need to define a static member variable holding your config values.
With this setup you can lazy load your properties values from an injected JPA source or also from any other CDI or EJB.
See the following example Code
#Startup
#Singleton
public class MyConfigSource implements ConfigSource {
public static final String NAME = "MyConfigSource";
public static Map<String, String> properties = null; // note to use static here!
#PersistenceContext(unitName = ".....")
private EntityManager manager;
#PostConstruct
void init() {
// load your data from teh JPA source or EJB
....
}
#Override
public int getOrdinal() {
return 890;
}
#Override
public String getValue(String key) {
if (properties != null) {
return properties.get(key);
} else {
return null;
}
}
#Override
public String getName() {
return NAME;
}
#Override
public Map<String, String> getProperties() {
return properties;
}
}
ConfigSources are POJO’s because if a CDI bean expected config to be injected into it at startup based on a ConfigSource that had dependencies on CDI’s you could get into startup looping issues.
For this reason the example CongigSoruce is constructed twice - once at the beginning from the Config-API and later from the CDI implemenation on #PostConstruct. With the static variable 'properties' we overload the values from the already constructed ConfigSource. Of course you can also separate the code in two classes if you like.

Dagger2 Android subcomponent injection in nonAndroid classes

Learning Dagger2 and maybe going off the rails here. I have a class - MapRoute that may or may not be needed in a Fragment. If MapRoute is needed, I want to create it and when the MapRoute is instantiated I want to inject it with dependencies created at the application level. I am also using Builder pattern to populate MapRouter.
Perhaps the generic question is when you are in nonAndroid classes (not Activity/Fragment/...) how can you inject dependencies from above? How to you construct the nonAndroid injector in place of AndroidInjection.inject(this)?
So my fragment is:
public class ActivityMapFragment extends DaggerFragment ... {
#Inject
MapRoute.Builder mapRouteBuilder;
private void plotRouteForMap(Cursor csr){
MapRoute.Builder builder = new MapRoute.Builder();
builder.setSupportMapFragment(supportMapFragment)
.setLocationExerciseRecord(ler)
.setMapType(mapType)
.setUseCurrentLocationLabel(useCurrentLocationLabel)
.setCursor(csr)
.setTitle(activityTitle)
.setActivityPhotosCallback(this);
mapRoute = builder.build();
mapRoute.plotGpsRoute();
}
...
MapRoute is: (Edit) added Builder code snippet
public class MapRoute ... {
#Inject
public DisplayUnits displayUnits; <<< Created at app level
#Inject
public PhotoUtils photoUtils; <<<< Create at app level
public MapRoute() {
// Use subcomponent builder
MapRouteSubcomponent component =
DaggerMapRouteSubComponent.builder().build(); <<< Want to do this
component.inject(this);
}
public static class Builder {
SupportMapFragment supportMapFragment;
LocationExerciseRecord ler;
boolean useCurrentLocationLabel;
int mapType;
Cursor cursor;
ActivityPhotosCallback activityPhotosCallback;
String title;
#Inject
public Builder() {
}
public Builder setSupportMapFragment(SupportMapFragment supportMapFragment){
this.supportMapFragment = supportMapFragment;
return this;
}
....
MapRouteSubcomponent best guess:
#Subcomponent(modules = {MapRouteModule.class, ApplicationModule.class})
public interface MapRouteSubcomponent {
// allow to inject into our MapRoute class
void inject(MapRoute mapRoute);
#Subcomponent.Builder
interface Builder extends SubComponentBuilder<MapRouteSubcomponent> {
Builder mapRouteModule(MapRouteModule mapRouteModule);
}
#Module
public class MapRouteModule {
// What to put here?
}
And finally a subcomponent builder:
// from https://github.com/Zorail/SubComponent/blob/master/app/src/main/java/zorail/rohan/com/subcomponent/SubComponentBuilder.java
public interface SubComponentBuilder<V> {
V build();
}
At this point I am at a stand on where to go from here.

How to Inject EPartService

I am developing e4 application. I want to inject EPartService outside the Part and Handler
when i am injecting EPartService then i will get null pointer error
public class DisplayRuntimePart {
#Inject EPartService partService;
private void displayPart(){
MPart part=partService.findPart("com.rcpe4.myproject.part.datapart");
mpart.setVisible(true);
partService.showPart(mpart, PartState.CREATE);
}
}
I am also read this question but till not solve my problem E4 EPartService findPart() throwing java.lang.Null Pointer Exception
Edit
I am inject EPartService in Part class. Class URI in Application.e4xml is bundleclass://com.abc.test/com.abc.test.part.MyPart in this class I am write code as follows.
Class Mypart{
#Inject EPartService prtservice;
#Inject
public MyPart() {
}
#PostConstruct
public void postConstruct(Composite parent) {
parent.setLayout(new FillLayout(SWT.HORIZONTAL));
htmlBrowser = new Browser(parent, SWT.NONE);
}
#PreDestroy
public void preDestroy() {
}
#Focus
public void onFocus() {
}
#Persist
public void save() {
}
public dispalyPart(){
MPart mpart=partService.findPart("com.abc.test.part.datapart"); **Here Getting Null Pointer Exception**
mpart.setVisible(true);
partService.showPart(mpart, PartState.CREATE);
}
}
Eclipse only does direct injection on objects that it 'knows' about - basically objects mentioned in the application model (e4xmi) files or created using something like EPartService.showPart.
If you want to do direct injection on objects that you create then you need to create them using ContextInjectionFactory. For example:
#Inject IEclipseContext context;
...
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
you can also do injection on a class created in the normal way with:
ContextInjectionFactory.inject(myClass, context);
(this will not do injection on the constructor).
Note: Since this code is using direct injection you must run it from a class that the Eclipse application model does know about such as a command handler or an MPart.

WickeTester - IllegalStateException: No CDI context bound to application

I have Wicket Form and ProjectNameValidator class:
#Inject
ProjectDao dao;
public ProjectNameValidator() {
CdiContainer.get().getNonContextualManager().inject(this);
}
the injection here is because the #Inject annotation works only in Wicket components or Behavior, here is null without the CdiContainer.get().getNonContextualManager().inject(this);
But when I have WicketTester, TestCreateprojectPage:
public class TestCreateProject {
private WicketTester tester;
#Before
public void setUp() throws Exception {
tester = new WicketTester();
}
#Test
public void createProjectPageRendersSuccessfully() {
tester.startPage(CreateProject.class);
tester.assertRenderedPage(CreateProject.class);
}
}
I'm getting exception on the Form in the CreateProject.java in ProjectNameValidator on this row:
CdiContainer.get().getNonContextualManager().inject(this);
IllegalStateException: No DCI Context bound to application.
You have a singleton CdiContainer in your application, that is not initialized in a test scope. So CdiContainer.get() is really null. Find out how to initialize CdiContainer test context, it depends on your implementation, and add it to test setUp().