#Transactional not working giving exception to add #Transactional - java

I am using jpa with Play 2.2.1 java .I have a method which finds all the the jobseekers
My controller function
#Transactional
public static Result index() {
return ok(views.html.admin.jobseeker.render("Your new application is ready.", Jobseekers.all()));
}
and model method
public static List<Jobseekers> all() {
#SuppressWarnings("unchecked")
List<Jobseekers> el = JPA.em().createQuery("from Jobseekers order by id").getResultList();
return el;
}
But i am getting exception
[RuntimeException: No EntityManager bound to this thread. Try to annotate your action method with #play.db.jpa.Transactional]
I dont know why its giving this error even though I have added #Transactional
Can anybody help me??
Thanks

Correct annotation is #Transactional not #Transaction

Related

Junit Test: findById method of the Repository

I am new in Junit tests and I have a question about it. Here you can see the method findById in my service class:
#Service
public class DefaultQuarterService implements QuarterService {
private final QuarterRepository quarterRepository;
public DefaultQuarterService(QuarterRepository quarterRepository) {
this.quarterRepository = quarterRepository;
}
#Override
public QuarterEntity findById(int id) {
return quarterRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(String.format("Quarter does not exist for id = %s!", id)));
}
}
And here is my QuarterRepository:
#Repository
public interface QuarterRepository extends CrudRepository<QuarterEntity, Integer> {
}
And here is my Junit implementation for this method:
#MockBean
private QuarterRepository quarterRepository;
#Test
public void throwExceptionWhenQuarterIdNotFound() {
int id = anyInt();
when(quarterRepository.findById(id))
.thenReturn(Optional.empty());
assertThatAnExceptionWasThrown(String.format("Quarter does not exist for id = %s!", id));
}
public void assertThatAnExceptionWasThrown(
String errorMsg
) {
expectException.expect(RuntimeException.class);
expectException.expectMessage(errorMsg);
}
Unfortunately test doesn't pass. Here the error in terminal:
java.lang.AssertionError: Expected test to throw (an instance of
java.lang.RuntimeException and exception with message a string
containing "Quarter does not exist for id = 0!")
Maybe it is so simple but I can not see what I am missing. I would be so happy if you can direct me. Thanks a lot!
As you mock your Repository it will return with Optional.empty() correctly, I think you should call your service's (which is Autowired) findById method. It will throw the exception actually.
First issue
In the assertThatAnExceptionWasThrown method you expect RuntimeException BUT in the service class you throw EntityNotFoundException, So I guess you should expect EntityNotFoundException in your test case.
Second issue
After this part of the code.
when(quarterRepository.findById(id))
.thenReturn(Optional.empty());
Why didn't you call your service method (findById)?
When you are returning the empty value, you should verify your condition with the service method you want to test it.
It should be something like this.
assertThatThrownBy(() -> defaultQuarterService.findById(id))
.isInstanceOf(ApiRequestException.class)
.hasMessageContaining("PUT_YOUR_EXCEPTION_MESSAGE_HERE");
This is a good sample for unit-test in the spring boot. You can check it out. Link
Try the above solutions and let me know it has been fixed or not. Good luck

How to do Rollback with Transactional Annotation

I am trying to do Transactional Rollback in my methods. Intentionally i am making the insert fails to find out . But i don't see its getting rolled back . Please help what i am missing.
#Service
public class ModesService implements IModesService{
ChargeRuleDao chargeRuleDao;
public ModesService(ChargeRuleDao chargeRuleDao){
this.chargeRuleDao = chargeRuleDao;
}
#Override
#Transactional(propagation = Propagation.REQUIRED)
public void process(ChargeRule chargeRule){
chargeRuleDao.deleteShippingChargeAttr(shippingChargeRuleID);
chargeRuleDao.deleteShippingCharge(shippingChargeRuleID);
chargeRuleDao.deleteShippingChargeDest(shippingChargeRuleID);
//Delete
chargeRuleDao.insertShipChargeFeedRule(chargeRule);
}
In DAOImpl class i have methods like below for all deletions and insertion.
#Override
public int deleteShippingChargeAttr(String test) {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("ABC" "ABC", Types.VARCHAR);
return jdbcTemplate.update(DELETE_QUERY, params);
}
You may try #Transactional(rollbackFor = XYZException.class).
XYZException should be an exception which should wrap all the exceptions/exception for which you want to rollback the transaction.
Rollback occurs by default for every unchecked exception. That means you need to throw some type unchecked exception, like for example
throw new NullPointerException();
in your insertShipChargeFeedRule(chargeRule);
more about #Transactional here https://javamondays.com/spring-transactions-explained/

JSON mapping problem: possible non-threadsafe access to the session

I am facing a problem due which is unknown to me, can you one have faced this problem?
JSON mapping problem: <package>ApiResponse["data"]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: possible non-threadsafe access to the session (through reference chain: <package>.ApiResponse["data"])
I have a standard API response pojo. Which I return every time with ResponseEntity. Everything is working fine, but sometimes I got that above error. I don't why this error occurred .
I got the below log from console
an assertion failure occurred (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to the session
org.hibernate.AssertionFailure: possible non-threadsafe access to the session
I think you are trying to share same Hibernate session within multiple threads. That's illegal.
Hibernate Sessions are not thread-safe whereas Hibernate SessionFactory is thread-safe.
So, make a separate DAO layer. Create single sessionfactory object and share it among the DAO classes.
Get a session for a single-threaded DB operation and close the session in that thread.
For example :
#Repository
public class DAO {
#Autowired
private SessionFactory sessionFactory;
public class performDBOperation(Object obj) {
Session session = sessionFactory.currentSession();
session.save(obj);
session.close();
}
}
Now, I have looked at your github code.
I saw the code Exec.java
#Service
public interface Exec {
#Async
#Transactional
public void run();
}
This is incorrect.
Updated :
public interface Exec {
public void run();
}
Update ExecImpl to this :
#Service
public class ExecImpl implements Exec {
#Autowired
private ExecDAO execDAO;
#Override
#Async
#Transactional
public void run() {
// example : create an object to save it.
Object object = ...;
execDAO.saveItem(object);
}
}
Create DAO layer :
Suppose ExecDAO interface and implementation ExecDAOImpl :
public interface ExecDAO {
public void saveItem(Object obj);
// keep here abstract method to perform DB operation
}
#Repository
public class ExecDAOImpl implements ExecDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void saveItem(Object obj) {
Session session = sessionFactory.currentSession();
session.save(obj);
session.close();
}
}
Looking at the code at the link you shared in the comment, I think that
#Async
#Transactional
is a dangerous thing.
I would suggest you to extract a method to do the transactions and try
what I mean is that,
interface ExecImpl{
#Async
void run(){
someThingElse.doTransaction();
}
}
interface SomeThingElse{
#Transactional
void doTransaction();
}
I am still not convinced this will help you. But this is something you can try.
I would also suggest to use readonly transactions for getting data and not have a single transaction for all purposes.
This blog explains why its not good to use these two annotations together whether on a class or on an interface

Spring Managed Custom Validator not being used from endpoint

I've been at this for a while, but I have a Spring managed custom validator that looks like the below, I have some print statements in there which I'll get to later
#Component
public class BulkUpdateValidator implements ConstraintValidator<ValidBulkUpdate, BulkUpdate> {
#Autowired
ObjectMapper mapper;
public BulkUpdateValidator(){
System.out.println(this.toString());
}
#PostConstruct
public void post(){
System.out.println(mapper);
System.out.println(this.toString());
}
public boolean isValid(BulkUpdate update, ConstraintValidatorContext context){
System.out.println(this.toString());
System.out.println(mapper);
}
... other validator methods ...
}
My controller method: (NOTE: my controller class is annotated with #Validated at the top)
#RequestMapping(...)
public #ResponseBody RestResponse bulkUpdate(#Valid #ValidBulkUpdate Bulkupdate bulkUpdate){
... stuff here ...
}
My Bean:
public class BulkUpdate {
#NotEmpty
public List<String> recordIds;
#NotEmpty
#Valid
public List<FieldUpdate> updates;
.... getters and setters ....
}
Here's my problem, when I execute the endpoint it get a NullPointerException when I attempt to use the autowired mapper. The output from the print statements I posted above are quite telling. In both the constructor and the #PostConstruct sections I get the same Object ID for the validator and I also get an ID for the mapper. However, once isValid is called, it prints out a different Object ID. I know the spring managed validator is being created, but it's not being used.
Furthermore, I've tried to remove the #ValidBulkUpdate annotation from the REST endpoint and put it inside a wrapper object, thinking that maybe #Valid was necessary to get spring to take over, like below:
public #ResponseBody RestResponse bulkUpdate(#Valid BulkupdateWrapper bulkUpdate){
... stuff here ...
}
And wrapper
public class BulkUpdateWrapper {
#ValidBulkUpdate
private BulkUpdate update;
.... getter and setter ....
}
This leaves me with a whole new error which is even weirder:
"JSR-303 validated property 'update.org.hibernate.validator.internal.engine.ConstraintViolationImpl' does not have a corresponding accessor"
I'm not sure where to turn, hopefully someone has an idea. Either how to get it to use the Spring managed validator, or how to remove that vague error when I use the object wrapper;
What's worse, is I have MockMvc based Integration tests for this that run flawlessly, this only happens when I deploy it.
UPDATE
So I kept my wrapper and changed #Valid to #Validated and now my error is the following: "NotReadablePropertyException: Bean property 'update.field' does not have a corresponding accessor for Spring data binding"
Fun fact, there is no property called "field"

Java Spring #Transactional method not rolling back as expected

Below is a quick outline of what I'm trying to do. I want to push a record to two different tables in the database from one method call. If anything fails, I want everything to roll back. So if insertIntoB fails, I want anything that would be committed in insertIntoA to be rolled back.
public class Service {
MyDAO dao;
public void insertRecords(List<Record> records){
for (Record record : records){
insertIntoAAndB(record);
}
}
#Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertIntoAAndB(Record record){
insertIntoA(record);
insertIntoB(record);
}
#Transactional(propagation = Propagation.REQUIRED)
public void insertIntoA(Record record){
dao.insertIntoA(record);
}
#Transactional(propagation = Propagation.REQUIRED)
public void insertIntoB(Record record){
dao.insertIntoB(record);
}
public void setMyDAO(final MyDAO dao) {
this.dao = dao;
}
}
Where MyDAO dao is an interface that is mapped to the database using mybatis and is set using Spring injections.
Right now if insertIntoB fails, everything from insertIntoA still gets pushed to the database. How can I correct this behavior?
EDIT:
I modified the class to give a more accurate description of what I'm trying to achieve. If I run insertIntoAAndB directly, the roll back works if there are any issues, but if I call insertIntoAAndB from insertRecords, the roll back doesn't work if any issues arise.
I found the solution!
Apparently Spring can't intercept internal method calls to transactional methods. So I took out the method calling the transactional method, and put it into a separate class, and the rollback works just fine. Below is a rough example of the fix.
public class Foo {
public void insertRecords(List<Record> records){
Service myService = new Service();
for (Record record : records){
myService.insertIntoAAndB(record);
}
}
}
public class Service {
MyDAO dao;
#Transactional (rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void insertIntoAAndB(Record record){
insertIntoA(record);
insertIntoB(record);
}
#Transactional(propagation = Propagation.REQUIRED)
public void insertIntoA(Record record){
dao.insertIntoA(record);
}
#Transactional(propagation = Propagation.REQUIRED)
public void insertIntoB(Record record){
dao.insertIntoB(record);
}
public void setMyDAO(final MyDAO dao) {
this.dao = dao;
}
}
I think the behavior you encounter is dependent on what ORM / persistence provider and database you're using. I tested your case using hibernate & mysql and all my transactions rolled back alright.
If you do use hibernate enable SQL and transaction logging to see what it's doing:
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.transaction=DEBUG
// for hibernate 4.2.2
// log4j.logger.org.hibernate.engine.transaction=DEBUG
If you're on plain jdbc (using spring JdbcTemplate), you can also debug SQL & transaction on Spring level
log4j.logger.org.springframework.jdbc.core=DEBUG
log4j.logger.org.springframework.transaction=DEBUG
Double check your autocommit settings and database specific peciular (eg: most DDL will be comitted right away, you won't be able to roll it back although spring/hibernate did so)
Just because jdk parses aop annotation not only with the method, also parse annotation with the target class.
For example, you have method A with #transactional, and method B which calls method A but without #transactional, When you invoke the method B with reflection, Spring AOP will check the B method with the target class has any annotations.
So if your calling method in this class is not with the #transactional, it will not parse any other method in this method.
At last, show you the source code:
org.springframework.aop.framework.jdkDynamicAopProxy.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
......
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping orfancy proxying.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
}

Categories