Grails 4: Save doesn't work in service method with prefix 'set' - grails

Using Grails 4.0.11 and OpenJDK 11, I came across a very strange behaviour that I was able to extract to a standalone project where I made sure it hasn't to do with plugins:
Given is a controller:
def updateOrder() {
def order = Order.get(params.id)
def result = shopService.setOrderPrintFileChecked(order)
redirect(action: "detailOrder", id: order.id)
}
and the service
#Transactional
class ShopService {
def setOrderPrintFileChecked(Order order) {
order.printFileChecked = new Date()
println("Validate: " + order.validate())
println("Errors: " + order.errors)
println("Dirty: " + order.isDirty())
def r = order.save(failOnError: true)
println("Result: " + r.printFileChecked)
return true
}
}
this does not save me the value to the database (tried MySQL+H2 default db).
If displays:
Validate: true
Errors: org.grails.datastore.mapping.validation.ValidationErrors: 0 errors
Dirty: true
Result: Sun Nov 21 15:58:17 CET 2021
if I change the method of ShopService from setOrderPrintFileChecked() to setorderPrintFileChecked() or even test() it works and the value is beeing saved correctly.**
it seems that the prefix + camelCase "setXyz" has a different behaviour. I'd like to know what it is and how to fix/prevent this case. Can provide full demo-application with the behaviour.
** Update**
This is de de-compiled service class with a non-setter-name:
public Object updateMyValue(final Order order) {
final Reference order2 = new Reference((Object)order);
final CustomizableRollbackTransactionAttribute $transactionAttribute = new CustomizableRollbackTransactionAttribute();
$transactionAttribute.setName("ch.pacdesigner.ShopService.updateMyValue");
final GrailsTransactionTemplate $transactionTemplate = new GrailsTransactionTemplate(this.getTransactionManager(), $transactionAttribute);
return $transactionTemplate.execute((Closure)new ShopService._updateMyValue_closure1((Object)this, (Object)this, order2));
}
this is the compiled method
public Object setOrderPrintFileChecked(final Order order) {
final CallSite[] $getCallSiteArray = $getCallSiteArray();
ScriptBytecodeAdapter.setGroovyObjectProperty($getCallSiteArray[0].callConstructor((Object)Date.class), (Class)ShopService.class, (GroovyObject)order, (String)"printFileChecked");
$getCallSiteArray[1].call((Object)order, (Object)ScriptBytecodeAdapter.createMap(new Object[] { "failOnError", true }));
return true;
}

As #Jeff Scott Brown stated, this behaviour is due to:
https://github.com/grails/grails-data-mapping/blob/c69add974963a3a1fcab27271d7ab4fa7c1faee2/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/transform/AbstractMethodDecoratingTransformation.groovy#L113

Related

Grails 3.3.11 Integration Test (GrailsApplication)

I am now in trouble with the configuration variable GrailsApplication in my Integration Tests. I don't know why, but, I am not managing to get its value when testing my api. I am using Grails 3.3.11. The value of the variable is being null and, due to it, I can't authenticate to perform the tests. I would appreciate your help. I am using Grails 3.3.11.
package br.com.xxx.id.test.integration
//Imports were moved out to simplify understanding
class IdControllerSpec extends Specification {
def grailsApplication
#Value('${local.server.port}')
Integer serverPort
String accessToken
String baseUrl
JSONObject documentPropertiesForTesting
JSONObject documentForTesting
String partTest
String userTest
String typeIdTest
String refreshToken
void setup(){
baseUrl = "http://localhost:${serverPort}/cmbid/api/v1"
partTest = "partTest"
}
void "Saving a new and valid document properties"() {
when:
refreshToken = grailsApplication.config.getProperty('refreshToken')
accessToken = "Bearer " + authenticateXxxAut()
documentPropertiesForTesting = createNewTestDocumentProperties()
typeIdTest = documentPropertiesForTesting.get("message").toString().substring(20,52)
then:
documentPropertiesForTesting.get("status") == "ok"
documentPropertiesForTesting.get("message").contains("properly saved!")
cleanup:
DocumentProperties.withNewSession {
def dp = DocumentProperties.findById(typeIdTest)
dp.delete(flush: true)
}
}
def authenticateXxxAut() {
CloseableHttpClient httpClient = HttpClients.createDefault();
String response = ""
try {
JSONObject responseBody
println('****************************')
println(grailsApplication.config.getProperty('aut.newTokenUrl'))
println(grailsApplication.config.getProperty('refreshToken)'))
println('****************************')
def httpPost = new HttpPost(grailsApplication.config.getProperty('aut.newTokenUrl') + grailsApplication.config.getProperty('refreshToken)'))
CloseableHttpResponse httpResponse = httpClient.execute(httpPost)
if (httpResponse.getStatusLine().getStatusCode() == 200) {
responseBody = new JSONObject(EntityUtils.toString(httpResponse.getEntity()))
response = responseBody.get("access_token")
} else {
response = httpResponse.getStatusLine().getStatusCode().toString()
}
} catch (Exception e){
print(e.getLocalizedMessage())
} finally {
httpClient.close()
return response
}
}
I've been upgrading a Grails 2.x app to version 3.3.11 and just referencing the (provided) variable serverPort worked for me. The IDE shows it as being uninitialized but running the tests, it gets the correct value assigned. I also have my test classes annotated with #Integration(applicationClass = Application.class).
Here's how I get the URL to point against:
def url = "http://localhost:${serverPort}${grailsApplication.config.getProperty('server.contextPath', String, '')}"

Jenkins Pipeline Execute Multiple FreeStyleProjects in Parallel [duplicate]

The script is not iterating through all the values of the 'modules' array.
class Module {
public String name = '';
public Boolean isCustom = false;
public Module(String name, Boolean custom){
this.name = name;
this.isCustom = custom;
}
}
//creates array from the ext_module env var
modules = [];
EXT_MODULE.split(',').each {
modules.add(new Module(it, false));
}
println modules;
modules.each {
println "MODULE NAME ::::: ${it.name}"
if(it.isCustom)
{
println "install custom";
} else {
println "install non custom";
}
};
This is the result of the run. The array shows 4 elements, but the code inside the .each black only executes once.
Running: Print Message
[Module#71f09325, Module#e1ddb41, Module#7069a674, Module#1f68f952]
Running: Print Message
MODULE NAME ::::: puppetlabs-ntp
Running: Print Message
install non custom
Running: End of Workflow
Finished: SUCCESS
The messages "Running: Print Message" and "Running: End of Workflow" indicate that you are using the new workflow plugin: https://wiki.jenkins-ci.org/display/JENKINS/Workflow+Plugin. This plugin currently has a bug causing at least some Groovy iterations involving a closure to be aborted after one iteration: https://issues.jenkins-ci.org/browse/JENKINS-26481
The workaround is to simply use an old school for loop (code below).
Also, NonCPS is another workaround.
There is an open issue for this matter. See here: https://issues.jenkins-ci.org/browse/JENKINS-26481
Update, Oct 24th, 2016
/**
* Dumps environment varibles to the log, using an old school for loop.
*/
import com.cloudbees.groovy.cps.NonCPS
def version = '1.0'
#NonCPS
def dumpEnvVars() {
def str = "Dumping build environment variables...\n"
for (Map.Entry<String, String> entry : currentBuild.build().environment) {
str += " ${entry.key} = ${entry.value}\n"
}
echo str
}
return this;
As of yesterday, the new Pipeline plugin was delivered in version 2.0 and correct this problem.
.each closures now work, but .collect still only iterate once.

Grails integration test doesn't work in test-app but is running correctly when starting alone

I am testing a service-class which do a little gorm-action.
If i run the test alone as integration-test it runs without failures and if i run test-app (does not matter if i run test-app integration:) my test fails and i got the error message, that the used domain classes:
"Method on class [xx.xx.User] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly."
Since its an integration-test, i dont want to mock the domain-classes and i just dont understand this error. I am using grails 2.3.5 with the correct tomcat and hibernate plugin:
#TestFor(EntryService)
//#Mock([User, Task, Entry, Admin])
class EntryServiceSpec extends Specification {
Entry entry1
EntryService entryService
User user
Task task
Date date
def setup() {
entryService = new EntryService()
user = User.findByEmail("test#test.de")
task = Task.findByName("something_inserted")
date = new Date().clearTime()
entry1 = new Entry()
entry1.comment = ""
entry1.effort = 23 as BigDecimal
entry1.user = user
entry1.bookedTask = task
entry1.bookedCosts = 300 as BigDecimal
entry1.entryDay = new Date().clearTime()
entry1.save(flush: true)
}
def cleanup() {
if(entry1 != null && entry1.id != null) {
entry1.delete()
}
}
void "Wished effort that shall be added is exceeding 24-hours day-constraints"() {
expect: "user has 23h erfforts, wants to add 2 more hours, it should exceed"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, date, new BigDecimal(2)) == true
}
void "Wished effort that shall be added is not exceeding 24-hours day-constraints"() {
expect: "user has 23h erfforts, wants to add 1 more hours, it should not exceed"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, date, new BigDecimal(1)) == false
}
void "null parameter should leed to return false"() {
expect: "user is null, method should return false"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(null, date, new BigDecimal(1)) == false
and: "date is null, method should return false"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, null, new BigDecimal(1)) == false
and: "wished-effort is null, method should return false"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, date, null) == false
}
}
Give credit to #dmahapatro who answered this in the comments above
You are running your test as a Unit test and not as a Integration test...
change you class signature to:
import grails.test.spock.IntegrationSpec
class EntryServiceSpec extends IntegrationSpec
notice that I also removed the #TestFor(EntryService)

neo4j 2.0 findNodesByLabelAndProperty not working

I'm currently trying the Neo4j 2.0.0 M3 and see some strange behaviour. In my unit tests, everything works as expected (using an newImpermanentDatabase) but in the real thing, I do not get results from the graphDatabaseService.findNodesByLabelAndProperty.
Here is the code in question:
ResourceIterator<Node> iterator = graphDB
.findNodesByLabelAndProperty(Labels.User, "EMAIL_ADDRESS", emailAddress)
.iterator();
try {
if (iterator.hasNext()) { // => returns false**
return iterator.next();
}
} finally {
iterator.close();
}
return null;
This returns no results. However, when running the following code, I see my node is there (The MATCH!!!!!!!!! is printed) and I also have an index setup via the schema (although that if I read the API, this seems not necessary but is important for performance):
ResourceIterator<Node> iterator1 = GlobalGraphOperations.at(graphDB).getAllNodesWithLabel(Labels.User).iterator();
while (iterator1.hasNext()) {
Node result = iterator1.next();
UserDao.printoutNode(emailAddress, result);
}
And UserDao.printoutNode
public static void printoutNode(String emailAddress, Node next) {
System.out.print(next);
ResourceIterator<Label> iterator1 = next.getLabels().iterator();
System.out.print("(");
while (iterator1.hasNext()) {
System.out.print(iterator1.next().name());
}
System.out.print("): ");
for(String key : next.getPropertyKeys()) {
System.out.print(key + ": " + next.getProperty(key).toString() + "; ");
if(emailAddress.equals( next.getProperty(key).toString())) {
System.out.print("MATCH!!!!!!!!!");
}
}
System.out.println();
}
I already debugged through the code and what I already found out is that I pass via the InternalAbstractGraphDatabase.map2Nodes to a DelegatingIndexProxy.getDelegate and end up in IndexReader.Empty class which returns the IteratorUtil.EMPTY_ITERATOR thus getting false for iterator.hasNext()
Any idea's what I am doing wrong?
Found it:
I only included neo4j-kernel:2.0.0-M03 in the classpath. The moment I added neo4j-cypher:2.0.0-M03 all was working well.
Hope this answer helps save some time for other users.
#Neo4j: would be nice if an exception would be thrown instead of just returning nothing.
#Ricardo: I wanted to but I was not allowed yet as my reputation wasn't good enough as a new SO user.

Grails domain class saves a NULL id property; leading to error when running web app

In this project I am attempting to save data returned by Yahoo Finance URL API. The URL to be accessed is "http://ichart.yahoo.com/table.csv?s=GOOG&a=0&b=1&c=2000&d=0&e=31&f=2010&g=w&ignore=.csv". I attempt to save the returned data as a String in my StockQuote.stockInfo parameter.
I get the following error with saving a StockQuote instance object:
Error 500: Internal Server Error
URI: /StockScreenerSD/stockQuote/tickerLookup
Class: org.h2.jdbc.JdbcSQLException
Message: NULL not allowed for column "STOCK_QUOTE"; SQL statement: insert into stock_quote (id, version, date_created, stock_info, ticker) values (null, ?, ?, ?, ?) [23502-164]
Around line 26 of grails-app/controllers/org/grails/finance/StockQuoteController.groovy
23:// def url = ("http://download.finance.yahoo.com/d/quotes.csv?s=" + stockQuote.ticker + "&f=xsna2t8pj1a").toURL()
24: def url = ("http://ichart.yahoo.com/table.csv?s=" +stockQuote.ticker+ "&a=0&b=1&c=2000&d=0&e=31&f=2010&g=w&ignore=.csv").toURL()
25: stockQuote.stockInfo = url.text.toString()
26: stockQuote.save()(flush: true)
27: def stockQuoteList = stockQuoteList()
28: render template: 'usedTickers', collection: stockQuoteList, var: 'stockData'
29: }
My Controller Code which attempts the saving action is as below:
package org.grails.finance
import grails.plugins.springsecurity.Secured
#Secured('IS_AUTHENTICATED_FULLY')
class StockQuoteController {
// def scaffold = true
def index() {
redirect (action:'getTicker')
}
def getTicker() {
def listing = stockQuoteList()
return [stockQuoteList: listing] // this is a map. key=>value
}
def tickerLookup = {
def stockQuote = new StockQuote(ticker: params.ticker)
def url = ("http://ichart.yahoo.com/table.csv?s=" +stockQuote.ticker+ "&a=0&b=1&c=2000&d=0&e=31&f=2010&g=w&ignore=.csv").toURL()
stockQuote.stockInfo = url.text.toString()
stockQuote.save()(flush: true)
def stockQuoteList = stockQuoteList()
render template: 'usedTickers', collection: stockQuoteList, var: 'stockData'
}
private stockQuoteList() {
StockQuote.list()
}
I hope this should be my last edit. Proof that friday becomes unproductive if you had a long busy week. :) Ok, here is how the setup has to be, it works for me:
//Domain class StockQuote
class StockQuote {
String ticker
String stockInfo
static mapping = {
stockInfo type: "text" //You have to set the type since the info is CLOB
}
}
//Controller Action
def tickerLookup = {
def stockQuote = new StockQuote(ticker: params.ticker)
def url = ("http://ichart.yahoo.com/table.csv?s=" +stockQuote.ticker+ "&a=0&b=1&c=2000&d=0&e=31&f=2010&g=w&ignore=.csv").toURL()
stockQuote.stockInfo = url.text.toString()
stockQuote.save(flush: true) //Look at how flush is used in save
def stockQuoteList = stockQuoteList()
render template: 'usedTickers', collection: stockQuoteList, var: 'stockData'
}
This above works for me and I am able to save the large CLOB response from the url to the table. Have a look at my test.

Resources