How to pass a service to an EmptyInterceptor class? - java

public class Auditing extends EmptyInterceptor {
#Resource
private ApplicationService applicationService;
public boolean onFlushDirty(Object entity, Serializable id,Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
if(applicationService == null){
System.out.println("applicationService is null");
}
return(true);
}
}
I observed for each hibernate action a new Auditing object is getting created and in onFlushDirty() it is always printing " applicationService is null "
Can anyone tell me how can i make ApplicationService available in an EmptyInterceptor?

I found a work around for this by having a Class with static applicationService property.
Now by creating a static reference for it i can use applicationService.
Its working for now.. Please post any better or efficient suggestions if you have :)
Regards,

You can create a class with application context object by implementing ApplicationContextAware interface.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ctx) {
context = ctx;
}
}
Now you can obtain your bean using below code.
applicationService = (ApplicationService ) ApplicationContextProvider.getApplicationContext().getBean("applicationService")
Above code can be used to obtain any other bean in future and would not require you to keep adding static beans.

Related

Inject spring beans into a non-managed class

I have this non-managed class that I want to inject spring beans (that I don't known a-priory what they are). How can I do that?
For example, let's say I have the following class:
public class NonManagedClass extends APIClass {
#Resource
private Service1 service;
#Resource
private Service2 service2;
// here i can declare many different dependencies
#Resource
private ServiceN serviceN;
#Override
public void executeBusinessStuffs() {
// business logics
}
}
I need in someway to let spring inject these dependencies in my class. I have access to these objects after created, so it's easy to me call any method that can accomplish this functionality. For example:
#Service
public void SomeAPIService {
#Resource
private BeanInjector beanInjector; // I'm looking for some funcionality of spring like this
public void someProcessingFunction(Class<? extends APIClass> clazz) throws Exception {
APIClass instance = clazz.getConstructor().newInstance();
beanInjector.injectBeans(instance);
instance.executeBusinessStuffs();
}
}
Does Spring have such functionality to inject beans based on fields annotation for a non-managed class?
Replace BeanInjector with ApplicationContext and you are almost there. From there you can get the AutowireCapableBeanFactory which provides some handy methods like createBean and autowireBean.
#Service
public void SomeAPIService {
#Resource
private ApplicationContext ctx;
public void someProcessingFunction(Class<? extends APIClass> clazz) throws Exception {
APIClass instance = ctx.createBean(clazz);
instance.executeBusinessStuffs();
}
}
or if you really like to construct stuff yourself instead of using the container:
#Service
public void SomeAPIService {
#Resource
private ApplicationContext ctx;
public void someProcessingFunction(Class<? extends APIClass> clazz) throws Exception {
APIClass instance = clazz.getConstructor().newInstance();
ctx.getAutowireCapableBeanFactory().autowireBean(instance);
instance.executeBusinessStuffs();
}
}

How to Autowire a class at runtime in a method

Is it possible to Autowire fields in a dynamic class?
I am getting a class name from the database and I want to autowire this class
Short Answer
That's not possible. Spring needs to know what Beans there are for injecting them.
Long Answer
You could #Autowire every possible bean into a class and then cache them in a Map, where the Class represents the key, and the Object the value. See below simplified example:
public class MyClass{
private final Map<Class<?>, Object> cache = new HashMap<>();
#Autowired
public MyClass(Service1 s1, Service2 s2){
// registering the beans
cache.put(Service1.class, s1);
cache.put(Service2.class, s2);
}
public <T> T getService(String className) throws ClassNotFoundException{
// getting the bean
Class<?> clazz = Class.forName(className);
return (T) cache.get(clazz);
}
}
Not sure it's a good idea, but you can inject a class like mentionned here :
Injecting beans into a class outside the Spring managed context
You can try this:
import javax.annotation.PostConstruct;
#Component
public class ApplicationContextAccessor {
private static ApplicationContextAccessor instance;
#Autowired
private ApplicationContext applicationContext;
public static T getBean(Class clazz) {
return instance.applicationContext.getBean(clazz);
}
#PostConstruct
private void registerInstance() {
instance = this;
}
}
Read this post : https://www.helicaltech.com/uses-of-springs-applicationcontext-while-using-reflection/

How to get the Spring Data JPA Repository Factory?

Since I got no answer to my previous question I tried to tweak the example given in the Spring documentation for customizing repositories. There ist a Method getRepository(Class repositoryInterface) which looks like It ist the right place to map my repository Overrides:
public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new MyRepositoryFactory<>(entityManager);
}
private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
#Resource
private Map<Class<?>, Class<?>> overrideRepositories;
public MyRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
//Test
overrideRepositories = new HashMap<>();
overrideRepositories.put(CustomerRepository.class, Customer2Repository.class);
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return super.getTargetRepository(metadata);
// return new MyRepositoryImpl<T, I>((Class<T>)
// metadata.getDomainClass(), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the
// JpaRepositoryFactory
// to check for QueryDslJpaRepository's which is out of scope.
return JpaRepository.class;
}
#SuppressWarnings("unchecked")
#Override
public <E> E getRepository(Class<E> repositoryInterface, Object customImplementation) {
if (overrideRepositories != null) {
Class<?> override = overrideRepositories.get(repositoryInterface);
if (override != null) {
repositoryInterface = (Class<E>) override;
}
}
return super.getRepository(repositoryInterface, customImplementation);
}
}
}
I configured it like this: #EnableJpaRepositories(repositoryFactoryBeanClass=MyRepositoryFactoryBean.class)
Normally you would autowire the repositories themselves which doesn't work because there are two Interfaces with the same Type and I don't know how to tell Spring which one to use.
If I autowire the factory instead, I can call getRepository each time I need a specific one. But how do I get this factory? Does Spring Data JPA somehow expose this as a bean? I can't find anything on google concerning this. Or is this approach entirely wrong?
You can use the ApplicationContext instance to get your MyRepositoryFactoryBean bean class. All you have to do is implement the ApplicationContextAware interface in order to get access to the ApplicationContext instance.
public class myClass implements ApplicationContextAware{
private static ApplicationContext ac;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.ac = applicationContext;
}
}
Now you can use ac.getBean("MyRepositoryFactoryBean") to get the factory directly from the ApplicationContext. Once you have that bean you can call getRepository on it.

How to make autowire object initialized in ApplicationListener?

I want to read data in ApplicationListener, but my object is not initialized. Below is my code:
AppContextListener.java
#Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
AppContext.getInstance();
}
}
AppContext.java
public class AppContext {
private static AppContext instance;
#Autowired
MyElasticsearchRepository repository;
public AppContext(){
InitData();
}
public static synchronized AppContext getInstance() {
if (instance == null) {
instance = new AppContext();
}
return instance;
}
private void InitData(){
List<MyEntity> dataList = repository.findAllEntities();//repository is null here
//.......
}
}
MyElasticsearchRepository.java
public interface MyElasticsearchRepository extends ElasticsearchRepository<MyEntity,String>
{ }
problem
As you can see in my code, at InitData(), repository is null. I don't
know why #Autowired MyElasticsearchRepository repository; does not
worked here.
Please show me how to fix this. Thank you very much.
There are a couple of things wrong with your code.
First you are using the singleton pattern which I would say is an anti-pattern especially when combined with auto wiring.
Second in your getInstance() method you are creating a new instance of AppContext yourself. This instance isn't managed by Spring so #Autowired is pretty much useless here, Spring is only able to inject dependencies into beans it knows about.
Instead make your AppContext a component (or service what ever you like). Remove the getInstance method and use constructor injection instead.
#Component
public class AppContext {
private final MyElasticsearchRepository repository;
#Autowired
public AppContext(MyElasticsearchRepository repository){
this.repository=repository;
}
...
}
Thirdly you are trying to use the #Autowired instance from the constructor (you are doing method call which expects it to be there), however auto wiring can only be done on an instance of a bean. So at that moment the auto wiring hasn't taken place and your variable will always be null. Instead of calling the method from the constructor either, use constructor inject or annotate the InitData method with #PostConstruct.
#PostConstruct
private void InitData(){
List<MyEntity> dataList = repository.findAllEntities();
...
}
Now that your AppContext is a component it will be detect by spring and you can simply inject it into your ApplicationListener.
#Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
private final AppContext appContext;
#Autowired
public AppContextListener(AppContext appContext) {
this.appContext=appContext;
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// Do your thing with appContext
}
}
Note: I prefer constructor injection for required fields and setter injection for optional fields. You should avoid field injection (i.e. #Autowired on instance fields) as that is considered a bad practice. See here why field injection is evil and should be avoided.
#Autowired will only work if bean is marked with Stereotype annotation (What's the difference between #Component, #Repository & #Service annotations in Spring?) or you explicitly define it in spring configuration.
AppContextListener.java
#Component // AFAIR not needed. Spring will create this bean when it will see that class implements `ApplicationListener` interface.
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private AppContext appContext;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
appContext.initData();
}
}
AppContext.java
#Component
public class AppContext {
#Autowired
MyElasticsearchRepository repository;
public void initData(){
List<MyEntity> dataList = repository.findAllEntities();//repository is null here
//.......
}
}
#Autowired will work only after AppContext object constructed. Since you try to access #Autowired element inside constructor, it doesn't exist.
Can't you just do this?
#Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicantContext context = event.getApplicationContext();
MyElasticsearchRepository repository = context.getBean(MyElasticSearchRepository.class);
//do stuff
}
}
http://docs.spring.io/autorepo/docs/spring/4.1.4.RELEASE/javadoc-api/org/springframework/context/event/ContextRefreshedEvent.html

How do I use Singleton in Dagger 1.x?

I read Christian Gruber's post and I started wondering how to use Application-wide Singletons.
In my application I have a class DBHelper, which main purpose is holding the keys to my database. I have also many (at least two) different DAOs. Now - I don't see a reason why would my several Activities/classes need more than just a single instance of DAO. What's more, why would a DAO need an instance of DBHelper just for itself? I'm pretty sure they can share, especially I don't predict a situation when both DAOs would want to perform some operation on my database at the same time. So let's see some classes:
DBHelper
#Singleton
public class DBHelper extends SQLiteOpenHelper {
//some not relevant configuration stuff
private Context context;
#Inject
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL, creating tables and stuff
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//dropping tables, creating a new one
onCreate(db);
}
}
example of DAO
public interface SomeDataDAO {
void hai();
}
public class SomeDataDAOImpl implements SomeDataDAO {
private DBHelper dbHelper;
public SomeDataDAOImpl(DBHelper dbHelper){
this.dbHelper = dbHelper;
}
#Override
public void hai() {
SQLiteDatabase database = dbHelper.getWritableDatabase();
dbHelper.doSomeDatabaseStuff()
}
}
SomeDataModule
#Module(
injects = { MainActivity.class, SomeServiceImpl.class }
)
public class SomeDataModule {
private Context appContext;
#Provides #Singleton
public SomeDataDAO provideSomeDataDao(DBHelper dbHelper){
return new SomeDataDAOImpl(dbHelper);
}
#Provides #Singleton
public ISomeService provideSomeService(SomeServiceImpl impl){
return impl;
}
#Provides
public Context getAppContext(){
return this.appContext;
}
public SomeDataModule(){
this.appContext = MainActivity.getAppContext();
}
}
Now let's see two examples of dependency consumers
public class MainActivity extends ActionBarActivity {
#Inject
SomeDataDAO someDataDAO;
private ObjectGraph objectGraph;
#Inject
ISomeService someService;
private static Context appContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
appContext = getApplicationContext();
objectGraph = ObjectGraph.create(SomeDataModule.class);
objectGraph.inject(this);
someService.doSomeStuff();
}
public static Context getAppContext() {
return appContext;
}
}
public class SomeServiceImpl implements ISomeService {
private ObjectGraph objectGraph;
#Inject public SomeDataDAO someDataDAO;
public SomeServiceImpl(){
objectGraph = ObjectGraph.create(GraphDataModule.class);
objectGraph.inject(this);
}
public void doSomeStuff(){
someDataDAO.hai();
}
}
It works, however when I inject(this) twice, Dagger obviously creates me two instances of DBHelper as it thinks "One Singleton fon one graph instance". How do I wrap my SomeDataModule in ApplicationModule, so I have only one instance of DBHelper in the entire app? Adding #Singleton to DBHelper unfortunately was not enough.
The easy, short and the answer which solves a minor design flaw and with that your problem is the following. Instead of creating a new ObjectGraph to inject the SomeDataDAO instance in your SomeServiceImpl, you really should pass the SomeDataDAO to your constructor. That is actually what dependency injection typically means: use the constructor of some object to inject its dependencies:
public class SomeServiceImpl implements ISomeService {
private final SomeDataDAO someDataDAO;
#Inject
public SomeServiceImpl(SomeDataDAO someDataDAO){
this.someDataDAO = someDataDAO;
}
public void doSomeStuff(){
someDataDAO.hai();
}
}
Now this is where the magic happens. Notice the #Inject annotation for the constructor? It tells Dagger to use this constructor whenever an instance of SomeServiceImpl is requested, and queries the ObjectGraph for its parameters.
So when you've got this Provides method below, Dagger already knows that SomeServiceImpl depends on SomeDataDAO, and uses your provideSomeDataDAO method to provide that instance. And, hey, it's a singleton, so this is the exact same instance as any other instance of SomeDataDAO retrieved by this ObjectGraph!
#Provides #Singleton
public ISomeService provideSomeService(SomeServiceImpl impl){
return impl;
}
In fact, you don't want to use ObjectGraph.inject(...) too often, you actually want to use the above methods. There are cases however, where you don't decide what the constructor looks like. In Android for example, these are Activity and View classes, amongst others. For these special cases, ObjectGraph.inject was created, so you can still inject your dependencies using Dagger.
Final note: In SomeServiceImpl I have made the someDataDAO private. As you probably know, this is the preferred way to handle instance fields, and using injectable constructors enables this.
Turns out this answer wasn't that short at all :O)

Categories

Resources