Existing transaction detected in JobRepository - Spring Batch with Grails Plugin - grails

Every time I start my batch job it throws an IllegalStateException and says it detected a transaction in JobRepository. I did some research and removed all #Transactional annotations in my code.
I use the Grails Spring Batch Plugin you can find here, and I work with Grails 2.3.11 and Java 8. My code looks like this:
SimpleJobBatchConfig.groovy
beans {
xmlns batch:"http://www.springframework.org/schema/batch"
batch.job(id: 'simpleJob') {
batch.step(id: 'printStep') {
batch.tasklet(ref: 'printHelloWorld')
}
}
printHelloWorld(SimpleJobTasklet) { bean ->
bean.autowire = 'byName'
}
}
BatchTestController.groovy
class BatchelorController {
def batchTestService
def index() {
}
def launchSimpleJob() {
batchTestService.launchSimpleJob()
}
}
BatchTestService.groovy
class BatchTestService {
def springBatchService
def launchSimpleJob() {
springBatchService.launch("simpleJob")
}
}
SimpleJobTasklet.groovy
class SimpleJobTasklet implements Tasklet {
#Override
RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
println("Hello World!")
return RepeatStatus.FINISHED
}
}

Grails services are transactional by default. You can customize the settings for the whole class or per-method with #Transactional but if you have no annotations it's the same as having a class-scope Spring #Transactional annotation.
To make your service non-transactional, add static transactional = false, e.g.
class BatchTestService {
static transactional = false
def springBatchService
...
}
}

Related

Can i inject services into urlmappings?

Is it possible to inject a service in UrlMappings.groovy? Something like below...
MyService.groovy
class MyService {
String foo() {
return "test"
}
}
UrlMappings.groovy
class UrlMappings {
def myService
static mappings = {
"/${myService.foo()}"
}
}
I am using Grails 3.0.11
Thank you

Grails integration test on a service: cannot set property on null object

I am using Grails 2.4.4 for my application, and using spock framework for tests.
class TaxpayerService {
static transactional = false
def springSecurityService
def setImporterDetails(TvfGen tvfGen) {
if (isTrader()) {
String taxPayerCode = springSecurityService?.principal?.getAt("tin")
def importerDetails = HistorizationSupport.withHistorizedFinder(BusinessLogicUtils.getWorkingDate(tvfGen)) {
Company.findByCode(taxPayerCode)
}
if (importerDetails) {
tvfGen.with {
impTaxPayerAcc = taxPayerCode
impName = importerDetails.name
}
}
}
}
}
Here is my integration test:
#Build([TvfGen])
class TaxpayerServiceSpec extends IntegrationSpec {
def taxpayerService
def springSecurityService
void setup() {
}
void tearDown() {
// Tear down logic here
}
void "test set importer details"() {
given:
def tvfGen = TvfGen.build()
springSecurityService = [principal: [tin: '0815790B', authorities: [ROLE_TRADER]]]
taxpayerService.springSecurityService = springSecurityService
taxpayerService.setImporterDetails(tvfGen)
expect:
tvfGen.impName == 'OMNI VALUE'
}
}
As a result I receive an error:
Cannot set property 'springSecurityService' on null object
java.lang.NullPointerException: Cannot set property 'springSecurityService' on null object
at TaxpayerServiceSpec.test set importer details(TaxpayerServiceSpec.groovy:34)

Grails code coverage not working

I am using Grails 2.2.4 and create JUnit Test for controller but code coverage not cover my test case of controller below are my test case detail.
//BuildConfig.groovy
plugins {
test ":code-coverage:2.0.3-3"
}
//MyControllerTests.groovy
#TestMixin(GrailsUnitTestMixin)
#TestFor(MyController)
#TestFor([Domain1,Domain2])
class MyControllerTests {
void setUp() {
controller.myService = new MyService()
}
void testAction1(){
controller.action1()
}
}
//mycontroller.groovy
class MyController {
def myService
def action1{
def msg = myService.myFirstAction()
}
}
//myservice.groovy
class MyService{
def myFirstAction(){
//logic which returns string
return 'my logic result'
}
}

Does using #Transactional disable the grails default transaction management

According to the grails docs, services are transactional by default. But, I know you can get more fine grained control of transactions by using the Transactional attribute.
If I have a service such as
class MyService {
#Transactional(...config...)
def method1() { }
def method2() { }
}
My understanding is that in this case, method1 will be transactional, but method2 will not.
If I have
class MyService {
def method1() { }
def method2() { }
}
Then both method1 and method2 will both be transactional.
Is this correct?
If you want your service as transactional set to true the transactional property (this isn't obligatory but if you want to make clear that the service is transactional):
class MyService {
static transactional = true
def method1() { }
def method2() { }
}
If you don't want to:
class MyService {
static transactional = false
#Transactional(...config...)
def method1() { }
def method2() { }
}
Another example (setting transactional property isn't obligatory, but helps to be clear - if you are not the only coding this):
import org.springframework.transaction.annotation.Transactional
class BookService {
#Transactional(readOnly = true)
def listBooks() {
Book.list()
}
#Transactional
def updateBook() {
// …
}
def deleteBook() {
// …
}
}
Another thing you can do is annotate the whole class and override the methods you need to be different:
import org.springframework.transaction.annotation.Transactional
#Transactional
class BookService {
#Transactional(readOnly = true)
def listBooks() {
Book.list()
}
def updateBook() {
// …
}
def deleteBook() {
// …
}
}
Hope this helps ;)
You can disable the Grails default transaction management using withTransaction closure for domains to manage your Transaction manually as follows:
Account.withTransaction { status ->
try {
//write your code or business logic here
} catch (Exception e) {
status.setRollbackOnly()
}
}
If an exception is thrown, then the Transaction will be rollbacked.

Is there any bug using both Spock and Spring Security plugin in same project?

I use both Spring and Spock plugins in my current project. I wrote a bunch of test cases in Spock. All are passing without any error (All are GREEN!). But the same tests are failing if I try to test the app after some time. I don't why this happens. This is the code (one of my failing test):
def 'list action: 1 user'() {
setup:
mockDomain(User,[userInstance])
expect:
controller.list() == [userInstanceList: [userInstance] , userInstanceTotal: 1]
params.max == 10
where:
userInstance = new User(username:"antoaravinth",password:"secrets")
}
I get a big error for this:
java.lang.NullPointerException: Cannot invoke method encodePassword() on null object
at mnm.schedule.User.encodePassword(User.groovy:34)
at mnm.schedule.User.beforeInsert(User.groovy:42)
at org.grails.datastore.gorm.events.DomainEventListener.invokeEvent(DomainEventListener.java:188)
at org.grails.datastore.gorm.events.DomainEventListener.beforeInsert(DomainEventListener.java:110)
at org.grails.datastore.gorm.events.DomainEventListener.onPersistenceEvent(DomainEventListener.java:73)
at org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener.onApplicationEvent(AbstractPersistenceEventListener.java:46)
at org.grails.datastore.mapping.engine.EntityPersister.cancelInsert(EntityPersister.java:227)
at org.grails.datastore.mapping.engine.NativeEntryEntityPersister.executeInsert(NativeEntryEntityPersister.java:1321)
at org.grails.datastore.mapping.engine.NativeEntryEntityPersister$1.run(NativeEntryEntityPersister.java:698)
at org.grails.datastore.mapping.core.impl.PendingOperationExecution.executePendingOperation(PendingOperationExecution.java:33)
at org.grails.datastore.mapping.core.AbstractSession.flushPendingOperations(AbstractSession.java:322)
at org.grails.datastore.mapping.core.AbstractSession.flushPendingInserts(AbstractSession.java:314)
at org.grails.datastore.mapping.core.AbstractSession.flush(AbstractSession.java:237)
at org.grails.datastore.mapping.query.Query.flushBeforeQuery(Query.java:596)
at org.grails.datastore.mapping.query.Query.list(Query.java:562)
at org.grails.datastore.mapping.query.Query.singleResult(Query.java:606)
at org.grails.datastore.gorm.GormStaticApi.count_closure11(GormStaticApi.groovy:311)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:301)
at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:34)
at org.grails.datastore.gorm.GormStaticApi.count(GormStaticApi.groovy:307)
at mnm.schedule.UserController.list(UserController.groovy:241)
at mnm.schedule.UserControllerSpec.list action: 1 user(UserControllerSpec.groovy:34)
The Domain class :
package mnm.schedule
import org.example.*;
class User extends SecUser {
Profile profile
String username
String password
static constraints = {
username(unique:true,size:3..15, blank:false)
password(blank:false)
String toString() {
this.username
}
static mapping = {
cache true
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
Set<SecRole> getAuthorities() {
SecUserSecRole.findAllBySecUser(this).collect { it.secRole } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
}
The same test is passing at times and at time throwing this error. Whats wrong here? How can it pass at times and fail at times?
Thanks in advance.
Check this blog as an example of mocking springSecurityService in domain objects
http://www.block-consult.com/blog/2011/08/17/inject-spring-security-service-into-domain-class-for-controller-unit-testing/ or check https://stackoverflow.com/a/9789619/206351

Resources