specflow external data using json with many property - specflow

I am trying to migrate from specflow excel to using a json data file and the external data plugin
Related to Specflow - using data from external file in feature file is there a walkthrough to setup a feature file, and json data file with new #property approach to data?
I have a Specflow feature like this, which originally came from Specflow Excel.
Feature: EndToEndId
Scenario Outline: Single Payment
Given a client <clientNo> called <cName>
And a broker <bName> with book ref <bRef>
When a deal to <buyOrSell> an amount <fromAmt> of <ccy1> for <ccy2> for value <vDate> at client rate <cRate> and bank rate <bRate>
Then create a deal <dealNo> with client amt <toCAmt> and cover amt <coverAmt> and PnL <PnL> and profit rate <pRate> and <bYes>
And add beneficiary <benName> and country <ctry> and pay type <payType> and charge <charge> and <abYes>
When a credit file <c1> with <c1Name> for <c1Amt> <c1Ccy> for value <c1Date> with ref <EndToEndId1>
Then CreditNotice gets <fIn1Type> for client <fIn1Client>
Examples:
| case | clientNo | cName | bName | bRef | buyOrSell | fromAmt | ccy1 | ccy2 | vDate | cRate | bRate | dealNo | toCAmt | coverAmt | PnL | pRate | bYes | benName | ctry | payType | charge | abYes | c1 | c1Name | c1Amt | c1Ccy | c1Date | EndToEndId1 | fIn1Type | fIn1Client |
| T1: 99549 ###### | 99549 | Gherkin Test | MERCURY | 01W3RG5638 | SELL | 100000 | EUR | GBP | SP | 0.89435 | 0.89935 | ###### | 89435 | 89935 | 500 | 1 | yes | Gherkin Ben | GB | CHAPS | NONE | yes | 99549 | Gherkin Test | 100000 | EUR | SP | 99549 ###### | FullFundsIn | Gherkin Test |
To use the with a json file for the data, am I going to need to define each property again like this:
#property:clientNo=clientNo
#property:cName=cName
#property:bName=bName
and a json data file like this:
{
"case": "T-9: 99549 ######",
"clientNo": "99549",
"cName": "Gherkin Test",
"bName": "MERCURY",
"bRef": "01W3RG5638",
"buyOrSell": "SELL",
"fromAmt": "100,000",
"ccy1": "EUR",
"ccy2": "GBP",
"vDate": "SP",
"cRate": " 0.894350 ",
"bRate": " 0.894350 ",
"dealNo": "######",
"toCAmt": "89,435.00",
"coverAmt": "89,435.00",
"PnL": "0.00",
"pRate": " 1.000000 ",
"bYes": " yes ",
"benName": "Gherkin Ben",
"ctry": "GB",
"payType": "CHAPS",
"charge": "NONE",
"abYes": "yes",
"c1": "99549",
"c1Name": "Gherkin Test",
"c1Amt": "100,000",
"c1Ccy": "EUR",
"c1Date": "SP",
"EndToEndId1": "99549 ######",
"fIn1Type": "FullFundsIn",
"fIn1Client": "Gherkin Test"
},
{
"case": "T-8: 1234 1234",
"clientNo": "99549",
"cName": "Gherkin Test",
"bName": "JUPITER",
"bRef": "01W3RG5639",
"buyOrSell": "SELL",
"fromAmt": "200,000",
"ccy1": "EUR",
"ccy2": "GBP",
"vDate": "SP",
"cRate": " 0.894350 ",
"bRate": " 0.894350 ",
"dealNo": "######",
"toCAmt": "178,870.00",
"coverAmt": "178,870.00",
"PnL": "0.00",
"pRate": " 1.000000 ",
"bYes": " yes ",
"benName": "Gherkin Ben",
"ctry": "GB",
"payType": "FASTER",
"charge": "NONE",
"abYes": "yes",
"c1": "99549",
"c1Name": "Gherkin Test",
"c1Amt": "200,000",
"c1Ccy": "EUR",
"c1Date": "SP",
"EndToEndId1": "1234 1234",
"fIn1Type": "BankRec",
"fIn1Client": "Gherkin Test"
}
Thanks for some pointers on how to get the json data into the specflow feature file.

The SpecFlow.ExternalData plugin is currently limited to a single parameter.
Please upvote the feature request at https://support.specflow.org/hc/en-us/community/posts/360015106078-Allow-multiple-parameters-to-be-used-with-External-Data-plugin to get this higher in our backlog priority.

There is a separate plugin called Specflow.Contrib.JsonData as part of Nuget packages which accepts JSON data as an input for specflow scenarios. It is an extension to the Specflow.ExternalData plugin. It also accepts multiple properties. Check out https://libraries.io/nuget/SpecFlow.Contrib.JsonData.

Related

pwm-backlight driver not being probed in u-boot

I'm trying to get my PWM working on a custom am33x board (same beagle-bone black target). For some reason I don't see the pwm-backlight driver being probed and thus no PWM as indicated on my scope. Here are my relevant source files:
dts snippet:
/dts-v1/;
#include "am33xx.dtsi"
#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "test";
compatible = "ti,am33xx";
chosen {
stdout-path = &uart0;
};
backlight: backlight {
status = "okay";
compatible = "pwm-backlight";
pwms = <&ehrpwm1 0 10000 0>;
brightness-levels = <0 10 20 30 40 50 60 70 80 90 99>;
default-brightness-level = <6>;
};
};
&am33xx_pinmux {
ehrpwm1_pins: pinmux-ehrpwm1-pins {
pinctrl-single,pins = <
AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_a2.ehrpwm1a */
>;
};
};
&ehrpwm1 {
u-boot,dm-spl;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&ehrpwm1_pins>;
};
defconfig
CONFIG_DM=y
CONFIG_CMD_DM=y
CONFIG_DM_VIDEO=y
CONFIG_DM_PWM=y
CONFIG_BACKLIGHT_PWM=y
pwm-backlight driver info
config BACKLIGHT_PWM
bool "Generic PWM based Backlight Driver"
depends on DM_VIDEO && DM_PWM
default y
help
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
This driver can be use with "simple-panel" and
it understands the standard device tree
(leds/backlight/pwm-backlight.txt)
(linux version)
https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt
and when I interrupt u-boot and use dm tree you can see that its not probed. Why?
=> dm tree
Class Index Probed Driver Name
-----------------------------------------------------------
root 0 [ + ] root_driver root_driver
simple_bus 0 [ + ] generic_simple_bus |-- ocp
simple_bus 1 [ ] generic_simple_bus | |-- l4_wkup#44c00000
simple_bus 2 [ ] generic_simple_bus | | |-- prcm#200000
simple_bus 3 [ ] generic_simple_bus | | `-- scm#210000
syscon 0 [ ] syscon | | `-- scm_conf#0
gpio 0 [ ] gpio_omap | |-- gpio#44e07000
gpio 1 [ ] gpio_omap | |-- gpio#4804c000
gpio 2 [ ] gpio_omap | |-- gpio#481ac000
gpio 3 [ ] gpio_omap | |-- gpio#481ae000
serial 0 [ + ] omap_serial | |-- serial#44e09000
mmc 0 [ + ] omap_hsmmc | |-- mmc#481d8000
timer 0 [ + ] omap_timer | |-- timer#48040000
timer 1 [ ] omap_timer | |-- timer#48042000
timer 2 [ ] omap_timer | |-- timer#48044000
timer 3 [ ] omap_timer | |-- timer#48046000
timer 4 [ ] omap_timer | |-- timer#48048000
timer 5 [ ] omap_timer | |-- timer#4804a000
misc 0 [ + ] ti-musb-wrapper | `-- usb#47400000
usb 0 [ + ] ti-musb-peripheral | `-- usb#47401000
eth 0 [ + ] usb_ether | `-- usb_ether
backlight 0 [ ] pwm_backlight `-- backlight

Grails 3.1.7 Spring Security Issue when create new User by GORM Scaffolding

I am doing my firsts steps in Grails (version 3.1.7), and I am doing an application which needs user authentication. This app is a web application that also provide some REST functionality, so I need a web login and a "rest" login with token.
I am using spring-security-core:3.1.0 and spring-security-rest:2.0.0.M2 for these propose and both logins are working properly.
Now I am having some troubles when I try to create a new user via the CRUD generated with grails generate-all package.User, I generated the view properly (I have a client class that the user could have or not so if the user has it I provide the client fields in the same create section too because a client can have only one user). When I save it I got a internal server error 500:
URI /web/webUser/save, Class java.lang.NullPointerException, Message null
in the file: \web\WebUserController.groovy
and the line is: webUser.save flush:true
the trace is:
Line | Method
80 | doFilter in grails.plugin.springsecurity.rest.RestLogoutFilter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 64 | doFilter in grails.plugin.springsecurity.web.UpdateRequestContextHolderExceptionTranslationFilter
| 53 | doFilter in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
| 143 | doFilter in grails.plugin.springsecurity.rest.RestAuthenticationFilter
| 62 | doFilter in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 58 | doFilter in grails.plugin.springsecurity.web.SecurityRequestHolderFilter
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run . . . in java.lang.Thread
Caused by NullPointerException: null
->> 47 | $tt__save in WebUserController.groovy
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 96 | doInTransaction in grails.transaction.GrailsTransactionTemplate$2
| 93 | execute . in grails.transaction.GrailsTransactionTemplate
| 96 | doInTransaction in grails.transaction.GrailsTransactionTemplate$2
| 93 | execute . in grails.transaction.GrailsTransactionTemplate
| 80 | doFilter in grails.plugin.springsecurity.rest.RestLogoutFilter
| 64 | doFilter in grails.plugin.springsecurity.web.UpdateRequestContextHolderExceptionTranslationFilter
| 53 | doFilter in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
| 143 | doFilter in grails.plugin.springsecurity.rest.RestAuthenticationFilter
| 62 | doFilter in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 58 | doFilter in grails.plugin.springsecurity.web.SecurityRequestHolderFilter
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
I am not sure if I have something wrong in the security plugin configuration or in the user and client domain class, or in the userController.
Edit: Updete info!
#Transactional(readOnly = true)
class WebUserController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
static namespace = 'web'
def springSecurityService
#Transactional
def save(WebUser webUser) {
if (webUser == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (webUser.hasErrors()) {
transactionStatus.setRollbackOnly()
respond webUser.errors, view:'create'
return
}
webUser.save flush:true // line where the NullPointerException is threw
if (webUser.isAdmin){
UserRole.create webUser, Role.findByAuthority('ROLE_ADMIN')
} else {
UserRole.create webUser, Role.findByAuthority('ROLE_CLIENT')
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'webUser.label', default: 'WebUser'), webUser.id])
redirect webUser
}
'*' { respond webUser, [status: CREATED] }
}
}
And the code in the domin:
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['isAdmin', 'springSecurityService']
boolean isAdmin
Client client
String name
String email
Date lastVisit
static hasMany = [orders: BOrder]
static constraints = {
username size: 5..15, blank: false, unique: true
password size: 5..15, blank: false, password: true
email email: true, blank: false, unique: true
name size: 0..50, nullable: true
lastVisit nullable: true
client nullable: true
}
The error happens when the client is either null or not. And debugging if I add a afterInsert in the WebUser domain class, I can see the Client id generated if it is not null, but the WebUser id is not generated, and I do not see any error message at that point.
Well I found where was the issue.
The problem was that I added a constraint to the password size, and the validate were executed before the password was hashed, so the validate pass, then the password was hashed and it doesn't have less than the 15 characters, so it failed when it try to persist the user in the database and then it threw the null pointer exception.
Removing or changing the max length restriction to the password, the problem were solved.
The only weird thing to me is the error message that I got, which didn't tell nothing relevant in my opinion.

Parse Command Outputting Horizontally

I have a script that parses a log file for the last 15 lines but it outputs the data in a horizontal line which I think interferes when I try to get an average of the numbers in the file.
Here's an example of the log file I'm parsing:
3/22/2016 9:11:21 AM 44.0
3/22/2016 9:11:22 AM 44.1
3/22/2016 9:11:23 AM 44.2
3/22/2016 9:11:24 AM 44.3
And here's my PowerShell command that parses the last 15 lines of the active log file.
$regexNUM = '\d+\.\d+'
$NUMLog = Get-ChildItem -Path 'C:\Users\Admin\Documents' |
Where-Object {$_.Name -match "LOGFILE"} |
Sort LastWriteTime | Select -Last 1
$NUMBERS = Get-Content -Path "C:\Users\Admin\Documents\$NumLog" -Tail 15 |
Select-String -Pattern $regexNum -AllMatches |
% { $_.Matches } | % { $_.Groups }
When I do a Write-Host $NUMBERS it outputs the data like this:
39.5 39.6 39.7 39.8 39.9 40.0 40.1 40.2 40.3 40.4 40.5 40.6 40.7 40.8 40.9
And here's how I'm trying to get the average of these 15 numbers:
$Average = $NUMBERS | Measure-Object -Average | Select Average
When I do Write-Host $Average it says:
Measure-Object : Input object "39.5" is not numeric.
At C:\Users\Admin\Documents\SampleTest.ps1:26 char:30
+ $Average = $NUMBERS | Measure-Object -Average | Select Average
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (39.5:Match) [Measure-Object], PSInvalidOperationException
+ FullyQualifiedErrorId : NonNumericInputObject,Microsoft.PowerShell.Commands.MeasureObjectCommand
I'm not sure why it would say the number 39.5 is not numeric but all I can assume is that it doesn't like it being horizontal with the spaces maybe. It throws one of those errors for each of the 15 numbers too.
Problem:
The problem in your code is that you are actually feeding objects of type System.Text.RegularExpressions.Match to the Measure-Object cmdlet, and not numbers.
The Write-Host command is automatically converting the Match object to text when it needs to output it to the console, and that makes you think it looks like numbers.
Solution:
To fix that, change the following line to get values inside the Match objects:
$NUMBERS = Get-Content -Path "C:\Users\Admin\Documents\$NumLog" -Tail 15 |
Select-String -Pattern $regexNum -AllMatches |
% { $_.Matches } | % { $_.Value }
Advice:
To fix problems like this yourself, you can use the the Get-Member cmdlet to check what is the type returned.
In your case, you can send the output of the second Get-Content cmdlet to Get-Member, instead of saving it to a variable:
Get-Content -Path "C:\Users\Admin\Documents\$NumLog" -Tail 15 |
Select-String -Pattern $regexNum -AllMatches |
% { $_.Matches } | % { $_.Groups } | Get-Member

How do I avoid getting duplicate key errors when using findOrSaveBy dynamic finders in Grails?

In a concurrent situation (asynchronous file uploads) where I try to create (or reuse) and attach keyword tags to images in an image library application i get a Unique index or primary key violation when creating Tag domain objects.
The controller calls a service method to add an image to the library and also the keyword tags that belongs to it.
Am I going about this the wrong way or am I missing something?
I'm currently using Grails 2.3.5.
Code:
class ImageAssetService {
def addTagToImage(ImageAsset imageAsset, String kw, String locale) {
def tagName = kw.toLowerCase(Locale.forLanguageTag(locale))
// OFFENDING LINE NEXT
def tag = Tag.findOrSaveByNameAndLocale(tagName, locale, [lock: true])
imageAsset.addToTags(tag)
if(!imageAsset.save()) {
throw new ImageAssetException()
}
imageAsset
}
def addTagsToImage(ImageAsset imageAsset, Set<String> keywords, String locale) {
keywords.each { kw ->
addTagToImage(imageAsset, kw, locale)
}
imageAsset
}
// CONTROLLER CALLS THIS METHOD
def addImageAsset(InputStream inputStream, String filename, long fileSize, long authorId, String timeZoneOriginal, String heading, String description, Set tags, String imageCollectionName) {
// Create the ImageAsset domain object
ImageAsset imageAsset = new ImageAsset(
filename: filename,
fileSize: fileSize,
author: Author.get(authorId),
timeZoneOriginal: TimeZone.getTimeZone(timeZoneOriginal),
heading: heading,
description: description
).save()
// Add any tags
addTagsToImage(imageAsset, tags, 'en')
/*
...
CODE REMOVED FOR BREVITY
....
*/
return imageAsset
}
}
class Tag {
String locale
String name
static hasMany = [ translations : Tag, synonyms : Tag ]
void setName(String name) { this.#name = name.toLowerCase() }
static constraints = {
locale unique: ['name']
}
static belongsTo = ImageAsset
static searchable = {
except = ['locale']
name boost: 2.0
translations component: [prefix: 'translations_', maxDepth: 2]
synonyms component: [prefix: 'synonyms_', maxDepth: 2]
}
static mapping = {
table 'tags'
}
}
class ImageAsset {
String filename
String heading
String description
String place
String city
String country
String gps
long fileSize = 0
int pixelWidth = 0
int pixelHeight = 0
Date dateTimeOriginal
TimeZone timeZoneOriginal
boolean enabled = true
Date dateCreated
static belongsTo = [
Author,
ConceptualImageCategory,
RepresentativeImageCategory,
ImageCollection
]
static hasOne = [ author : Author ]
static hasMany = [
conceptualCategories : ConceptualImageCategory,
representativeCategories : RepresentativeImageCategory,
collections : ImageCollection,
metadata : Metadata,
tags : Tag
]
static constraints = {
filename blank: false
heading nullable: true
description nullable: true
place nullable: true
city nullable: true
country nullable: true
gps nullable: true
pixelWidth nullable: true
pixelHeight nullable: true
dateTimeOriginal nullable: true
timeZoneOriginal nullable: true
}
static mapping = {
description type: 'text'
}
static searchable = {
//only = ['filename', 'heading', 'description', 'tags', 'metadata']
author component: [prefix: 'author_']
tags component: [prefix: 'tags_']
metadata component: [prefix: 'metadata_']
}
}
Error message:
Unique index or primary key violation: "CONSTRAINT_INDEX_27 ON PUBLIC.TAGS(NAME, LOCALE) VALUES ( /* key:11 */ 895, 0, 'en', 'work')"; SQL statement:
insert into tags (id, version, locale, name) values (null, ?, ?, ?) [23505-173]. Stacktrace follows:
Message: Unique index or primary key violation: "CONSTRAINT_INDEX_27 ON PUBLIC.TAGS(NAME, LOCALE) VALUES ( /* key:11 */ 895, 0, 'en', 'work')"; SQL statement:
insert into tags (id, version, locale, name) values (null, ?, ?, ?) [23505-173]
Line | Method
->> 331 | getJdbcSQLException in org.h2.message.DbException
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 171 | get in ''
| 148 | get . . . . . . . . . . in ''
| 101 | getDuplicateKeyException in org.h2.index.BaseIndex
| 68 | add . . . . . . . . . . in org.h2.index.TreeIndex
| 52 | add in org.h2.index.MultiVersionIndex
| 125 | addRow . . . . . . . . . in org.h2.table.RegularTable
| 127 | insertRows in org.h2.command.dml.Insert
| 86 | update . . . . . . . . . in ''
| 79 | update in org.h2.command.CommandContainer
| 235 | executeUpdate . . . . . in org.h2.command.Command
| 154 | executeUpdateInternal in org.h2.jdbc.JdbcPreparedStatement
| 140 | executeUpdate . . . . . in ''
| 102 | doCall in org.grails.datastore.gorm.GormStaticApi$_methodMissing_closure2
| 105 | addTagToImage . . . . . in se.originalab.imagedb.ImageAssetService
| 94 | doCall in se.originalab.imagedb.ImageAssetService$_addTagsToImage_closure3
| 93 | addTagsToImage . . . . . in se.originalab.imagedb.ImageAssetService
| 45 | addImageAsset in ''
| 31 | upload . . . . . . . . . in se.originalab.imagedb.UploadController
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . . . . . . . . in grails.plugin.cache.web.filter.AbstractFilter
| 53 | doFilter in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
| 49 | doFilter . . . . . . . . in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
| 82 | doFilter in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 1110 | runWorker . . . . . . . in java.util.concurrent.ThreadPoolExecutor
| 603 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run . . . . . . . . . . in java.lang.Thread
I found a solution myself. I had to break out the creation of a Tag into it's own transaction. Each call to Tag.findOrSaveByNameLocale() is now called through a synchronized service method from the controller. Then I add them to the ImageAsset afterwards.
One problem with this is that if the creation of the ImageAsset fails the Tags will still be persisted, but in my use case this is not a big problem.

Grails "don't flush the Session after an exception occurs" error message

I see that this error message has been posted several times already in the context of hibernate.
I am getting this error while using grails service and a domain class, any help will be really appreciated
Domain class
class Coupon {
Date dateCreated
Date lastUpdated
String code
String email
String address
String state
String city
String zip
def couponCodeGeneratorService
def beforeValidate() {
println code+"---------8-"
code = couponCodeGeneratorService.generate()
println code+"----------"
}
static constraints = {
email blank:false,email:true
address blank:false
state blank:false
city blank:false
zip blank:false
}
}
Service
class CouponCodeGeneratorService {
Random randomGenerator = new Random()
def serviceMethod() {
}
def generate(){
def group1 = randomGenerator.nextInt(9999)+"";
def group2 = randomGenerator.nextInt(9999)+"";
def group3 = randomGenerator.nextInt(9999)+"";
def group4 = randomGenerator.nextInt(9999)+"";
return group1.padLeft(4,"0") +group2.padLeft(4,"0")+group3.padLeft(4,"0")+group4.padLeft(4,"0")
}
}
The error I am getting is
---------8-
4844634041715590----------
4844634041715590---------8-
| Error 2012-09-10 11:32:54,938 [http-bio-8080-exec-7] ERROR hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
Message: null id in com.easytha.Coupon entry (don't flush the Session after an exception occurs)
Line | Method
->> 19 | beforeValidate in com.easytha.Coupon
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 46 | onApplicationEvent in org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
| 24 | save . . . . . . . in com.easytha.CouponController
| 186 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . . . . . in grails.plugin.cache.web.filter.AbstractFilter
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run . . . . . . . in ''
^ 662 | run in java.lang.Thread
| Error 2012-09-10 11:32:54,944 [http-bio-8080-exec-7] ERROR errors.GrailsExceptionResolver - AssertionFailure occurred when processing request: [POST] /EasyTha/coupon/save - parameters:
zip: asdf
address: asd
email: s.s#s.xom
state: asd
code:
create: Create
city: asdf
null id in com.easytha.Coupon entry (don't flush the Session after an exception occurs). Stacktrace follows:
Message: null id in com.easytha.Coupon entry (don't flush the Session after an exception occurs)
Line | Method
->> 19 | beforeValidate in com.easytha.Coupon
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 46 | onApplicationEvent in org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
| 24 | save . . . . . . . in com.easytha.CouponController
| 186 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . . . . . in grails.plugin.cache.web.filter.AbstractFilter
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run . . . . . . . in ''
^ 662 | run in java.lang.Thread
I am not very familiar with Hibernate, also is this a correct way to create a coupon code that looks like a credit card number?
I suspect the problem may be that the CouponCodeGeneratorService is transactional. Therefore, when you call the service method from inside your beforeValidate you're opening and closing a transaction (even though you don't touch the database inside the method), which among other things will cause another flush of the session.
Try making the service non-transactional:
static transactional = false

Resources