Unexpected ClassCastException... using EJB - ejb-3.0

I am facing a very small problem which is driving me mad..
I am calling a business method 'public List getPsubcategoryList()' from a stateless sessionbean named SlBrowseProducts .. this method used entitymanager instance to retrieve a list of Objects from Database Table mapped to Entity class named Psubcategory. this I did using a namedQuery. The list returned contains elements of type Object, I have to attach a iterator named myIterator to list and cast eachof the myIterator.next()'s to the type Psubcategory to make the result element useful and run any getters on it. However this casting returned the following error..
SEVERE: java.lang.ClassCastException: entitybeans.Psubcategory cannot be cast to entitybeans.Psubcategory
I tried googling extensively to find the cause for it.. to which I came across something called 'ClassLoader Hell' which might be causing it..
Is there any solution to this problem. Is there any other way around this... I have tried not using Iterator and instead using for loop ... but even then I have to cast.. which again lands me to the same problem..
Please Help m tight on schedule.
====================JSP PAGE==================
List<Psubcategory> subcategoryList1 = slbp.getProductSubcategories();
if(subcategoryList1.size()!=0){
for(int i=0;i<subcategoryList1.size();i++){
Psubcategory temp = subcategoryList1.get(i);
System.out.print(temp.getSubcategory());
}
}
======================SLBrowseProducts.java======================
#Stateless
#LocalBean
public class SLBrowseProducts implements TestInterface {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("INNOVATIVE-INDOORSPU");
EntityManager em = emf.createEntityManager();
#Override
public List getProductSubcategories(){
List subcategoryList=em.createNamedQuery("Psubcategory.findAll").getResultList();
return subcategoryList;
}
}

#Stateless
#LocalBean
public class SLBrowseProducts implements TestInterface {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("INNOVATIVE-INDOORSPU");
EntityManager em = emf.createEntityManager();
#Override
public List<Psubcategory> getProductSubcategories(){
List<Psubcategory> subcategoryList=
em.createNamedQuery("Psubcategory.findAll").getResultList();
return subcategoryList;
}
}
============================================================================================
List<Psubcategory> subcategoryList1 = slbp.getProductSubcategories();
for(Psubcategory temp : subcategoryList1){
System.out.print(temp.getSubcategory());
}

Related

Hibernate LazyInitialization exception in console Spring Boot with an open session

I'm not sure if anyone has experienced this particular twist of the LazyInitialization issue.
I have a console Spring Boot application (so: no views - everything basically happens within a single execution method). I have the standard beans and bean repositories, and the typical lazy relationship in one of the beans, and it turns out that unless I specify #Transactional, any access to any lazy collection automatically fails even though the session stays the same, is available, and is open. In fact, I can happily do any session-based operation as long as I don't try to access a lazy collection.
Here's a more detailed example :
#Entity
class Path {
... `
#OneToMany(mappedBy = "path",fetch = FetchType.LAZY,cascade = CascadeType.ALL)
#OrderBy("projectOrder") `
public List<Project> getProjects() {
return projects; `
}`
}
Now, the main method does something as simple as this:
class SpringTest {
... `
#Autowired
private PathRepository pathRepository;
void foo() {
Path path = pathRepository.findByNameKey("...");
System.out.println(path.getProjects()); // Boom <- Lazy Initialization exception}
}
Of course if I slap a #Transactional on top of the method or class it works, but the point is - why should I need that? No one is closing the session, so why is Hibernate complaining that thereĀ“s no session when there is one?
In fact, If I do:
void foo() {
System.out.println(entityManager.unwrap(Session.class));
System.out.println(entityManager.unwrap(Session.class).isOpen());
Path basic = pathRepository.findByNameKey("...");
System.out.println(entityManager.unwrap(Session.class));
System.out.println(entityManager.unwrap(Session.class).isOpen());
System.out.println(((AbstractPersistentCollection)basic.projects).getSession());
Path p1 = pathRepository.findByNameKey("....");
}
I get that the session object stays the same the whole time, it stays open the whole time, but the internal session property of the collection is never set to anything other than null, so of course when Hibernate tries to read that collection, in its withTemporarySessionIfNeeded method it immediately throws an exception
private <T> T withTemporarySessionIfNeeded(LazyInitializationWork<T> lazyInitializationWork) {
SharedSessionContractImplementor tempSession = null;
if (this.session == null) {
if (this.allowLoadOutsideTransaction) {
tempSession = this.openTemporarySessionForLoading();
} else {
this.throwLazyInitializationException("could not initialize proxy - no Session");
}
So I guess my question would be - why is this happening? Why doesn't Hibernate store or access the session from which a bean was fetched so that it can load the lazy collection from it?
Digging a bit deeper, it turns out that the repository method executying the query does a
// method here is java.lang.Object org.hibernate.query.Query.getSingleResult()
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
if (SharedEntityManagerCreator.queryTerminatingMethods.contains(method.getName())) {
...
EntityManagerFactoryUtils.closeEntityManager(this.entityManager); // <--- Why?!?!?
this.entityManager = null;
}
...
}
and the above closeEntityManager calls unsetSession on all collections:
SharedSessionContractImplementor session = this.getSession();
if (this.collectionEntries != null) {
IdentityMap.onEachKey(this.collectionEntries, (k) -> {
k.unsetSession(session);
});
}
But why?!
(Spring Boot version is 2.7.8)
So, after researching more it appears that this is standard behavior in Spring Boot - unless you use your own EntityManager, the one managed automatically by Spring is either attached to a #Transactional boundary, or opens and closes for each query.
Some relevant links:
Does Entity manager needs to be closed every query?
Do I have to close() every EntityManager?
In the end, I ended using a TransactionTemplate to wrap my code into a transaction without having to mark the whole class #Transactional.

JPA - Spanning a transaction over multiple JpaRepository method calls

I'm using SpringBoot 2.x with SpringData-JPA accessing the database via a CrudRepository.
Basically, I would like to call the CrudRepository's methods to update or persist the data. In one use case, I would like to delete older entries from the database (for the brevity of this example assume: delete all entries from the table) before I insert a new element.
In case persisting the new element fails for any reason, the delete operation shall be rolled back.
However, the main problem seems to be that new transactions are opened for every method called from the CrudRepository. Even though, a transaction was opened by the method from the calling service. I couldn't get the repository methods to use the existing transaction.
Getting transaction for [org.example.jpatrans.ChairUpdaterService.updateChairs]
Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.deleteWithinGivenTransaction]
Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.deleteWithinGivenTransaction]
I've tried using different Propagation. (REQUIRED, SUPPORTED, MANDATORY) on different methods (service/repository) to no avail.
Changing the methods #Transactional annoation to #Transactional(propagation = Propagation.NESTED) sounded that this would just do that, but didn't help.
JpaDialect does not support savepoints - check your JPA provider's capabilities
Can I achieve the expected behaviour, not using an EntityManager directly?
I also would like to avoid to having to be using native queries as well.
Is there anything I have overlooked?
For demonstration purposes, I've created a very condensed example.
The complete example can be found at https://gitlab.com/cyc1ingsir/stackoverlow_jpa_transactions
Here are the main (even more simplified) details:
First I've got a very simple entity defined:
#Entity
#Table(name = "chair")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Chair {
// Not auto generating the id is on purpose
// for later testing with non unique keys
#Id
private int id;
#Column(name = "legs", nullable = false)
private Integer legs;
}
The connection to the database is made via the CrudRepository:
#Repository
public interface ChairRepository extends CrudRepository<Chair, Integer> {
}
This is being called from another bean (main methods here are updateChairs and doUpdate):
#Slf4j
#Service
#AllArgsConstructor
#Transactional
public class ChairUpdater {
ChairRepository repository;
/*
* Initialize the data store with some
* sample data
*/
public void initializeChairs() {
repository.deleteAll();
Chair chair4 = new Chair(1, 4);
Chair chair3 = new Chair(2, 3);
repository.save(chair4);
repository.save(chair3);
}
public void addChair(int id, Integer legCount) {
repository.save(new Chair(id, legCount));
}
/*
* Expected behaviour:
* when saving a given chair fails ->
* deleting all other is rolled back
*/
#Transactional
public void updateChairs(int id, Integer legCount) {
Chair chair = new Chair(id, legCount);
repository.deleteAll();
repository.save(chair);
}
}
The goal, I want to achieve is demonstrated by these two test cases:
#Slf4j
#RunWith(SpringRunner.class)
#DataJpaTest
#Import(ChairUpdater.class)
public class ChairUpdaterTest {
private static final int COUNT_AFTER_ROLLBACK = 3;
#Autowired
private ChairUpdater updater;
#Autowired
private ChairRepository repository;
#Before
public void setup() {
updater.initializeChairs();
}
#Test
public void positiveTest() throws UpdatingException {
updater.updateChairs(3, 10);
}
#Test
public void testRollingBack() {
// Trying to update with an invalid element
// to force rollback
try {
updater.updateChairs(3, null);
} catch (Exception e) {
LOGGER.info("Rolled back?", e);
}
// Adding a valid element after the rollback
// should succeed
updater.addChair(4, 10);
assertEquals(COUNT_AFTER_ROLLBACK, repository.findAll().spliterator().getExactSizeIfKnown());
}
}
Update:
It seems to work, if the repository is not extended from either CrudRepository or JpaRepository but from a plain Repository, definening all needed methods explicitly. For me, that seems to be a workaround rather than beeing a propper solution.
The question it boils down to seems to be: Is it possible to prevent SimpleJpaRepository from opening new transactions for every (predefined) method used from the repository interface? Or, if that is not possible, how to "force" the transaction manager to reuse the transaction, opened in the service to make a complete rollback possible?
Hi I found this documentation that looks will help you:
https://www.logicbig.com/tutorials/spring-framework/spring-data/transactions.html
Next an example take from the previous web site:
#Configuration
**#ComponentScan
#EnableTransactionManagement**
public class AppConfig {
....
}
Then we can use transactions like this:
#Service
public class MyExampleBean{
**#Transactional**
public void saveChanges() {
**repo.save(..);
repo.deleteById(..);**
.....
}
}
Yes this is possible. First alter the #Transactional annotation so that it includes rollBackFor = Exception.class.
/*
* Expected behaviour:
* when saving a given chair fails ->
* deleting all other is rolled back
*/
#Transactional(rollbackFor = Exception.class)
public void updateChairs(int id, Integer legCount) {
Chair chair = new Chair(id, legCount);
repository.deleteAll();
repository.save(chair);
}
This will cause the transaction to roll back for any exception and not just RuntimeException or Error.
Next you must add enableDefaultTransactions = false to #EnableJpaRepositories and put the annotation on one of your configuration classes if you hadn't already done so.
#Configuration
#EnableJpaRepositories(enableDefaultTransactions = false)
public class MyConfig{
}
This will cause all inherited jpa methods to stop creating a transaction by default whenever they're called. If you want custom jpa methods that you've defined yourself to also use the transaction of the calling service method, then you must make sure that you didn't annotate any of these custom methods with #Transactional. Because that would prompt them to start their own transactions as well.
Once you've done this all of the repository methods should be executed using the service method transaction only. You can test this by creating and using a custom update method that is annotated with #Modifying. For more on testing please see my answer in this SO thread. Spring opens a new transaction for each JpaRepository method that is called within an #Transactional annotated method

Weird issue in Lazy load

I am totally confused with one issue Spring data + hibernate
We have a Restful service which we are migrating to V2.
So the old controller looks like
#Api(tags = {"assignments"})
#RestController
#CheckedTransactional
public class AssignmentListController {
#Inject
private AssignmentListService assignmentListService;
//REST function
public list() {....}
}
The REST function list calls AssignmentListService to load assignments, which is a collection, and loads some data lazily. Its works excellent.
What I did is I copied this controller as name AssignmentListControllerV2, and it looks like
#Api(tags = {"assignments"})
#RestController
#CheckedTransactional
public class AssignmentListControllerV2 {
#Inject
private AssignmentListService assignmentListService;
#Inject
private AssignmentDtoMapper assignmentDtoMapper;
public list() {...}
}
The code is same except AssignmentDtoMapper bean added, which is created using MapStruct.
Now the problem, When I call this new service, somehow I get a Lazy Load exception. The error is
could not initialize proxy - no Session
I desperately need some help as I have no clue whats happening. I have just copied the code in a new class and its failing.
The exception is actually pretty clear, Hibernate can't load the lazy fetched member because there is no persistence context open when you hit it.
I suppose that in the V2 the:
#Inject
private AssignmentDtoMapper assignmentDtoMapper;
is to change some JPA business entity into DTO?
It's probably the source of the exception if you try to map not loaded member there.
If you want to avoid the exception on unitiliazed proxy you can try something like
public boolean isProxyInitialized(Object obj){
if(obj instanceof HibernateProxy){
HibernateProxy proxy = (HibernateProxy) obj;
return !proxy.getHibernateLazyInitializer().isUninitialized();
}
return obj != null;
}
It should return true if the member as bean fetched otherwise false.

Spring AOP ProxyFactory class - how to retrieve original bean property value

I am trying to understand the behaviour of
org.springframework.aop.framework.ProxyFactory
So the problem I have encountered is (simplified to remove confidential info)
public class A {
#Autowired
public A(B b) {
System.out.println(b.num);
}
}
#Repository
public class B {
public int num = 10;
}
Where above prints 0 rather than 10.
After some investigation I have come to
AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization
where it apply bean processors to this bean (B), the processor that wiped out the value in "b.num" is
PersistenceExceptionTranslationPostProcessor
and I digged into that and got to
AbstractAdvisingBeanPostProcessor.postProcessAfterInitialization
specifically the following code snippet
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
proxyFactory.setTarget(bean);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(getProxyClassLoader());
So seems like proxyFactory.getProxy will actually wipe out the value of the "num" field.
So I have created a simple test
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new B());
B proxiedB = proxyFactory.getProxy();
I can see proxiedB.num is 0 rather than 10.
I am not sure if the above proxying code make sense/wrote in the right way.
My question is that I am trying to understand why ProxyFactory.getProxy() would wipe out the information and how to get the original information from this proxied bean?

Why doesn't Mockito's when() get triggered?

I need to test a service class, but when I try to mock the dao class, it doesn't get triggered, thus not able to use ThenReturn().
I think that the problem is because I use an interface for my Dao and #Autowired in the service class (Spring MVC 3.1):
The interface:
public interface TestDao {
int createObject(Test test) throws NamingException;
}
The implementation:
#Repository
public class TestDaoImpl implements TestDao {
#Override
public int createObject(Test test) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new InsertNewTest(test), keyHolder);
return ((java.math.BigDecimal)keyHolder.getKey()).intValue();
}
}
The service:
public class RegTest {
#Autowired
TestDao testDao;
public int regTest(int .....) {
.
.
int cabotageId = testDao.createObject(test);
}
}
In the test I have:
#RunWith(MockitoJUnitRunner.class)
public class TestRegService {
#InjectMocks
private RegTest regTest = new RegTest();
#Mock
TestDao testDao;
#Test()
public void test() {
.
when(testDao.createObject(null)).thenReturn(100);
.
}
testDao.createObject(null) returns 0 (due to being mock'ed) and not 100 as I is trying to achieve.
Can anybody help, please?
Problem solved!
It was the passing test-object to createObject() that did not match. Using
testDao.createObject(any(Test.class))
did the trick!
If your test is actually passing a value to createObject, then when(testDao.createObject(null)... never gets matched. Rather than matching on null, you could match any instance of Test with testDao.createObject(any(Test.class))...
Also when you tried later to supply new Test() as the argument to match, it will literally try to match on that exact instance of Test, but presumably your real code is new-ing up a different one. So the use of Matchers.any(Test.class) as the parameter to match is the way to go.
Mockito injection mechanism don't know about Spring #Autowired or CDI #Inject annotations. It just tries to find the best candidate given the type and the name of the mock, and it can lookup private fields too. See the javadoc of #InjectMocks : http://docs.mockito.googlecode.com/hg/1.9.0/org/mockito/InjectMocks.html
The semantic you are using is correct, though if you are experiencing issues, I would rather look for incorrect interactions or incorrect arguments.
Are you sure the test variable in regTest.regTest(int...) is really null when passed to testDao.createObject(test) ?
I don't know if this is a typo in the example, but you have RegTest.regTest() calling createTest() rather than createObject(). Otherwise, I don't think #Autowired has anything to do with it, since your test itself is not running in a container with Spring management. If it is not a typo, and createTest is in fact a real and different method from createObject, then the default behaviour of a mocked object in Mockito is to return the appropriately-typed zero for numeric return types.
I think that you're right about the autowire not getting called. You could inject the dao yourself using the setTestDao() call instead. Mockito also supports spy which allows you to trace the objects code and just replace functions instead.

Resources