I am trying to Inject a class into my entity listener created by my jpa provider. The following code throws a PersistenceException - unable to build hibernate SessionFactory (which I expected). From my research it seems like jpa 2.1 supports dependency injection. I am missing some type of binding/provides for guice to know about this class. My guess is it has to be some type of run time binding.
public class EntityListener {
private SomeService service;
#Inject
public EntityListener(SomeService service) {
this.service = service;
}
#PostLoad
public void load(Object o){
//use service here
}
}
Related
I've a Spring Boot application with the Spring Data JPA and two entities mapped to a database. My application is set to recreate the database on every startup. Now i want to create some instances of these POJOs, persist them in the database so I've some data to test my application with in the ongoing development process.
What is the best way to do that?
What i tried so far:
My class to add the sample data
public class DBSampleAdditor {
#PersistenceContext
private EntityManager em;
#Transactional
public void addSampleData() {
// creating POJO instances and persist them with em.perists()
}
}
I tried to call these functions in the main of my ApplicationClass
#SpringBootApplication()
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
DBSampleAdditor dbsa = new DBSampleAdditor();
dbsa.addSampleData();
}
}
That didnt work at all, as the EntityManager never got an Instance from the persistence unit.
I also tried to create a CommandLineRunner:
#Component
public class PTCommandLineRunner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
System.out.println("Adding sample data...");
DBSampleAdditor dbsa = new DBSampleAdditor();
dbsa.addSampleData();
}
}
But that one seemed to never been called in the startup process.
You can use method with #PostConstruct with #Component to insert data at startup.
#PostConstruct will be invoked after the bean has been created, dependencies have been injected, all managed properties are set, and before the bean is actually set into scope.
Just inject your database repository in the class marked with #Component and call your injected database repository inside the method marked with #PostConstruct
Example:
#Component
public class DbInit {
#Autowired
private UserRepository userRepository;
#PostConstruct
private void postConstruct() {
User admin = new User("admin", "admin password");
User normalUser = new User("user", "user password");
userRepository.save(admin, normalUser);
}
}
In order to use spring managed components like the EntityManager the objects need to spring Beans, which basically means they are created inside the spring context and can utilise the IoC container.
In the example above, running the DbSampleAdditor class from the main method is outside the spring context, so the beans like PersistenceContext wont get injected.
One fairly simple way to do this inside the spring context is to add an ApplicationListener for the ApplicationReadyEvent
#Component
class Initialise implements ApplicationListener<ApplicationReadyEvent> {
#Autowired
private final DbSampleAdditor db;
#Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
db.addSampleData();
}
}
When the application ready event fires all the necessary spring bean wiring is set up so when it runs the addSampleData method, things like the EM are good to go.
Other approaches for setting up a DB for spring boot are documented here
Instead of creating an object DBSampleAdditor, try to autowire it so that it is available on application startup. #Autowired DBSampleAdditor DBSampleAdditor Then you try to add sample data within the run method
I have written 2 WebSocket ServerEndpoints that inject Services that themselves interact with the Database using injected instances of the JPA EntityManager.
The application is a web application deployed on a Tomcat Server, using Jersey as JAX-RS implementation and Hibernate as JPA Provider.
Sometimes it happens that the EntityManager is closed when trying to the DB inside the Endpoints. Also I fear I might have produced code that triggers a Memory Leak.
This is the custom ServerEndpoint.Configurator that I am using (based on https://gist.github.com/facundofarias/7102f5120944c462a5f77a17f295c4d0):
public class Hk2Configurator extends ServerEndpointConfig.Configurator {
private static ServiceLocator serviceLocator;
public Hk2Configurator() {
if (serviceLocator == null) {
serviceLocator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
ServiceLocatorUtilities.bind(serviceLocator, new ServicesBinder()); // binds the "normal" Services that interact with the DB
ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
#Override
protected void configure() {
bindFactory(EntityManagerFactory.class).to(EntityManager.class);
}
});
}
}
#Override
public <T> T getEndpointInstance(final Class<T> endpointClass) throws InstantiationException {
T endpointInstance = super.getEndpointInstance(endpointClass);
serviceLocator.inject(endpointInstance);
return endpointInstance;
}
}
In the rest of the application I am using the same ServicesBinder, but a different Binder for the EntityManager.
The EntityManagerFactory looks like this:
public class EntityManagerFactory implements Factory<EntityManager> {
private static final javax.persistence.EntityManagerFactory FACTORY = Persistence.createEntityManagerFactory("PersistenceUnit");
#Override
public final EntityManager provide() {
return FACTORY.createEntityManager();
}
#Override
public final void dispose(final EntityManager instance) {
instance.close();
}
}
It is loaded with the Scope RequestScoped (only there, not in the WebSocket Endpoints).
I tried creating an EntityManager instance for every access in my DAOs, but then I would run into org.hibernate.LazyInitializationExceptions eventually since my DTOs need an open EntityManager (implicitly).
Any suggestions on how to circumvent the issues I'm having?
Okay, I managed to fix my issue by simply rewriting the EntityManager handling to create and close an EntityManager every time I interact with the database.
In Spring project I can use #Autowired annotation.
#Service
public class DefaultUserService implements UserService {
...
#Autowired
private UserDao userDao;
But I don't understand how do it in JavaEE project. I found:
#Inject
private AvayaDao avayaDao;
But my avayaDao is NULL. I tried add annotation
#Default
public class AvayaService {
...
#Inject
private AvayaDao avayaDao;
but not helped. It id my Dao:
public interface AvayaDao extends BaseDao<AvayaSdr> {
List<AvayaSdr> getAll();
void insertCdr(AvayaSdr avayaSdr);
}
It is My Service:
#Default
public class AvayaService {
private static AvayaService instance;
#Inject
private AvayaDao avayaDao;
public synchronized static AvayaService me() {
if (instance == null) {
instance = new AvayaService();
}
return instance;
}
public Set<String> selectAllLoadedAVAYAcmCDRFiles() {
Set<String> result = new HashSet<>();
List<AvayaSdr> resultList = avayaDao.getAll();
for (AvayaSdr avayaSdr : resultList) {
result.add(avayaSdr.getHashValue());
}
return result;
}
public void insertCdr(String fileHash) {
AvayaSdr avayaCmCdr = new AvayaSdr("", fileHash, 0);
avayaDao.insertCdr(avayaCmCdr);
}
java.lang.NullPointerException
Either the AvayaDao must be an EJB and annotated with #Stateless or #Singleton or you use CDI injection and an empty beans.xml file is needed (http://docs.oracle.com/javaee/6/tutorial/doc/gjbnz.html) if you are using Java EE 6. In Java EE 7 the attribute bean-discovery-mode="all" must be set (https://docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm).
UPDATE 1:
Enterprise Java Beans are POJOS annotated with #Stateless, #Statefull or #Singleton, that are managed by the EJB container inside the application server. They are able to access container specific services like the TimerService, the security context and aspects like transaction support and monitoring. Stateless enterprise java beans are also pooled by the application server.
UPDATE 2:
#Tiny Your right, but if AvayaDao is no EJB and your application contains a beans.xml file, where interceptors or other CDI specific POJOS are registered the default bean-discovery-mode is 'annotated' and the injection will not work with not annotated POJOS and explicitly setting the 'all' value is needed (http://www.adam-bien.com/roller/abien/entry/when_your_di_breaks_bean). Another option would be using no beans.xml if you explicitly know, that your application is only deployed in JAVA EE 7 environments.
Is there any analog of OpenEntityManagerInViewInterceptor for CLI application?
I am trying to use Spring's CrudRepository with JPA data source backed by Hibernate 4 in CLI application.
My main method creates an instance of the class containing this method and injects services using context.getBeanFactory().autowireBean(object);.
Services for data fetching have methods annotated with #Transactional. These methods invoke CrudRepository's methods.
But I receive org.hibernate.LazyInitializationException when I try to manage related entities in the CLI application.
Is there any workaround to have lazy loading working in the CLI application outside the #Transactional methods like OpenEntityManagerInViewInterceptor for web applications?
Look at the following snippet:
public class test {
#Autowired
public UserService userService;
public static void main(String[] args) {
test test = new test();
//injecting dependencies into test
test.run();
}
private void run() {
User user = userService.findById(42);
System.out.println(user.getLogin()); //User was fetched successfully
Address address = new Address("London");
user.addAddress(address);//Exception in thread "main" java.lang.RuntimeException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection
}
}
I would say there isn't one for CLI because there's no notion of View as in MVC pattern. However I suspect your problem is due to ineffective declarative transaction management.
For a CLI application, ensure you have properly setup datasource, EntityManagerFactory and declarative transaction managemeent.
A good practice is to enclose your business / DAO code in service / repository classes annotated with #Service, #Repository, #Component or other appropriate spring annotation, create your own ApplicationContext and obtain reference to your services:
// UserDAO.java ----------------------------------------
#Repository
public class UserDAO {
#PersistenceContext private EntityManager em;
#Transactional
public User findById(long id) {
// ...
}
}
// UserService.java ----------------------------------------
#Service
public class UserService {
#Autowired private UserDAO userDAO;
// ...
}
// MainClass.java ----------------------------------------
public class MainClass {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/root-context.xml");
UserService userService = context.getBean(UserService.class);
// more code here..
context.close();
}
}
Autowiring and declarative transaction will still work as per normal as long as the bean is created by Spring container.
I am attempting to use mocks in my integration test and am not having much luck. I am using Spring 3.1.1 and Mockito 1.9.0, and the situation is as follows:
#Component
public class ClassToTest {
#Resource
private Dependency dependency;
}
and
#Component
public class Dependency {
#Resource
private NestedDependency nestedDependency;
}
Now, I want to do an integration test of ClassToTest using Spring's JavaConfig. This is what I have attempted, and it doesn't work:
#Test
#ContextConfiguration
public class ClassToTestIntegrationTest {
#Resource
private ClassToTest classToTest;
#Resource
private Dependency mockDependency;
#Test
public void someTest() {
verify(mockDependency).doStuff();
// other Mockito magic...
}
#Configuration
static class Config {
#Bean
public ClassToTest classToTest() {
return new ClassToTest();
}
#Bean
public Dependency dependency() {
return Mockito.mock(Dependency.class);
}
}
}
I have simplified my setup to make the question easier to understand. In reality I have more dependencies and only want to mock some of them - the others are real, based on config imported from my prod #Configuration classes.
What ends up happening is I get a NoSuchBeanDefinitionException saying that there are no beans of type NestedDependency in the application context. I don't understand this - I thought Spring would receive Mockito's mocked instance of Dependency and not even look at autowiring it. Since this isn't working I end up having to mock my entire object graph - which completely defeats the point of mocking!
Thanks in advance for any help!
I had the same problem and I found another solution.
When Spring instantiate all your beans, it will check if it's a Mockito Mock and in this case, I return false for injection property. To use it, just inject it in a Spring context
Code below:
public class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
private static final MockUtil mockUtil = new MockUtil();
public MockBeanFactory() {
super();
}
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockUtil.isMock(bean);
}
}
What Mockito does when mocking classes is it creates a subclass using cglib having some fancy name like: Dependency$EnhancerByMockito (IIRC). As you probably know, subclasses inherit fields from their parent:
#Component
public class Dependency {
#Resource
private NestedDependency nestedDependency;
}
public class Dependency$EnhancerByMockito extends Dependency{
//...
}
This means Spring still sees the field in base class when presented with mock. What you can do:
Use interfaces, which will cause Mockito to employ dynamic proxies rather than CGLIB-generated classes
Mock NestedDependency - I know it will just cascade the problem one level further
Disable #Resource annotation scanning for tests