I want to use EHCache in my grails application. I want to cache a method with #Cacheable.
I am testing this scenario:
Simple test class:
class MyTestClassB {
def a
def b
#Override
boolean equals(Object obj) {
println ("New A" + this.a)
println ("Olda A" + obj.a)
if (this.a != obj.a) {
return false
}
return super.equals(obj)
}
}
Method to be cached in a service class:
#Transactional
class HelpService {
#Cacheable('newcache')
def inlineCacheService(def param) {
println ("I am in the function")
MyTestClass a = new MyTestClass()
a.paramA = new Date()
a.paramB = [
id: "1",
data: "f"
]
return a
}
}
So I call the method in the controller:
MyTestClassB c1 = new MyTestClassB()
c1.a = "paramc1"
render "1: " + helpService.inlineCacheService(c1).paramA
c1.a = "paramc1neu"
render "<br/>1: " + helpService.inlineCacheService(c1).paramA
The problem in this scenario is: I changed the value of parameter object, so I expect that I don't get the cached value. But the second call of inlineCacheService reads the value from the cache. What is the problem here? Do I missunderstand something?
The hashCode was missing. After implementation the cache works now as excpected. Thanks to #rcgeorge23
Related
I am trying to mock the groovy.sql.Sql call(query, params[], closure) class.
Below is method, within a DatabaseService class file, that I am attempting this on.
public void getUsers(List<User> developerList, Sql sql) {
sql.call("{? = call GETUSERS()}", [Sql.resultSet(OracleTypes.CURSOR)]) { result ->
while (result.next()) {
User user = new User()
user .email = result.EMAIL
user .lastName = result.LASTNAME
}
}
}
My mock does achieve the task, however, I do not want the mocked closure to execute. I want to mock the .call(,,_) method to only skip the database logic, and return back a list to the closure in the getUsers() method. I want the closure to execute in getUsers() method, not the mocked up method.
Below is the mockup I have written in SPOCK.
void "test getUsers(list,sql) some results"() {
DataSource mockedSource = Mock(DataSource)
Sql mockedSql = Mock(Sql)
DatabaseService databaseService = new DatabaseService()
databaseService.dataSource = mockedSource
List<User> userList= new ArrayList<>();
when:
databaseService.getUsers(userList, mockedSql)
then:
1 * mockedSql.call(_, _, _) >> { return [[EMAIL: "A", LASTNAME: "B"]] }
userList.size() == 1
}
As imagined, this mockup overwrites the original method closure, and my list is never populated.. I certainly do not want to rewrite my class to use Java, nor can I change the stored procedure that is executed.
try :
int resultSetIdx = 0
def resutSet = Mock(ResultSet)
...
then:
1 * mockedSql.call(_, _, _) >> { args -> args[2].call(resultSet) }
2 * mockedResultset.next() >> { ++resultSetIdx > 1 ? false: true}
1 * mockedResultset.getString("EMAIL") >> "A"
In the getUsers method() change
user.lastName = result.LASTNAME
user.email = result.EMAIL
To
user.lastName = result.getString("LASTNAME")
user.email = result.getString("EMAIL")
However, you shouldn't mock Sql, but rewrite your service/dao layer to be more testable. test the dao with an inmemory db, and the service layer with a mocked dao.
I am testing ehcache for grails. I am not able to invalidate my cache.
My test code:
The service method:
#Transactional
class HelpService {
#Cacheable('newcache')
def inlineCacheService(def param) {
println ("I am in the function")
MyTestClass a = new MyTestClass()
a.paramA = new Date()
a.paramB = [
id: "1",
data: "f"
]
return a
}
The code in the controller:
render "<br/>4: " + helpService.inlineCacheService("test").paramA
Thread.sleep(2000)
CacheManager cm = CacheManager.getInstance();
Cache myCache = cm.getCache("newcache")
myCache.removeAll()
render "<br/>4: " + helpService.inlineCacheService("test").paramA
I am getting a null pointer exception on remove all. Why the newcache can not be found? I am using this name in the cachable annotation and have it in my CacheConfig.groovy.
My CacheConfig.groovy:
config = {
cache {
name 'inlinecache'
//Overwrite these, inherit rest
timeToLiveSeconds 20
}
cache {
name 'newcache'
//Overwrite these, inherit rest
timeToLiveSeconds 30
}
defaultCache {
//Just inherit from defaults
}
defaults {
timeToIdleSeconds 120
timeToLiveSeconds 120
eternal false
overflowToDisk false
maxElementsInMemory 10000
maxElementsOnDisk 10000000
memoryStoreEvictionPolicy="LRU"
}
}
With this code it works:
CacheManager.ALL_CACHE_MANAGERS.each { cm ->
println (cm.getName())
String[] names = cm.getCacheNames();
for (String name : names)
{
Cache cache = cm.getCache(name);
println (name)
cache.removeAll();
}
};
But isn't there a better solution?
Best regards
Peter
I am not a Grails specialist, but what you have is most likely two CacheManager defined:
one by Grails - most likely a named one
then in your code snippet the CacheManager.getInstance() ends up creating the default un-named CacheManager that does not know anything about your configured cache.
So I would look up the Ehcache configuration you are specifying and I would update the code in your snippet to get to the same CacheManager.
Use CacheManager.getCacheManager(String name) to get to an existing CacheManager. If you pass null, it will get the CacheManager named with CacheManager.DEFAULT_NAME.
I am new with grails and am developing a web application.
I have a List of long values which is getting from ids of Domain class objects.
Initially this List is like [1,2,3]. I need to use this list of values in my service class for saving the associations.
But the same List is getting in service class as [49,50,51]
Why this difference of 48 is occurred? and how can i get the List as same as i sent.
Controller class:
def createQuestion(CreateQuestionCommand createQuestionCmd) {
if( createQuestionCmd.hasErrors() ) {
render(view:"create_question", model:[createQuestionCmd:createQuestionCmd , tags:Tag.list()])
} else {
Question question = new Question()
question.title=createQuestionCmd.title
question.description=createQuestionCmd.description
List tags= createQuestionCmd.tags
question = questionService.create(question,tags)
render(view: "question_submitted")
}
}
service class:
def create(Question question, List<Long> tagId) {
List<Tag> tagList=getTagsById(tagId)
question.save( failOnError:true )
Iterator itr=tagList.iterator();
while(itr.hasNext()) {
Tag tag=itr.next()
question.addToTags(tag).save()
}
}
def getTagsById(List tagId){
Iterator itr=tagId.iterator();
List<Tag> tags
while(itr.hasNext()) {
long id=itr.next()
println "value of id is : "
println id
println id.getClass().getName()
Tag tag=Tag.findById(id)
tags.add(tag)
}
return tags
}
CreateQuestionCmd.tags are List<String> and you are trying to place that to List<Long>
Just pass the object to service and create question object.In groovy we create the object in map format.In java only, we need iterator to loop collection.In groovy we use each closure to loop the collection. Try it will work out. Any problem in the following code let me know.I will help.
Controller class:
def createQuestion(CreateQuestionCommand createQuestionCmd) {
if(createQuestionCmd.hasErrors() ) {
render(view:"create_question", model:[createQuestionCmd:createQuestionCmd , tags:Tag.list()])
} else {
questionService.create(createQuestionCmd)
render(view: "question_submitted")
}
}
service class:
def create(def createQuestionCmd) {
def question = new Question(title:createQuestionCmd.title,description:createQuestionCmd.description)
question.save(flush:true)
List tagIds= createQuestionCmd.tags
tagIds.each{
def tag=Tag.findById(id)
question.addToTags(tag).save(flush:true)
}
}
I'm trying to use the Grails shopping cart plugin found here: http://grails.org/plugin/shopping-cart
I was able to successfully install the plugin in my application, as well as inject the service in my Controller:
class TestController {
def shoppingCartService
def index() {
def s = new DomainObj(name: "A Plain Ole Domain Object")
s.addToShoppingCart()
}
}
This appears to be adding the product to my shopping cart, as I expected. However, the problem I'm encountering now is actually listing the items out from the cart. According to the debugger, after running the above code, the shopping cart does indeed have an item (s) in it, as it returns:
com.metasieve.shoppingcart.ShoppingItem : 1
The item is properly being added to the cart, but now I would like to actually list the name of the item out again, so in this case, I want to display the name A Plain Ole Domain Object. How do I do this?
I'm unsure of the syntax for getting the actual objects back from the cart. The documentation doesn't describe how to do this clearly, as it merely states that the following should work:
def checkedOutItems = shoppingCartService.checkOut()
checkedOutItems.each {
println it['item']
println it['qty']
}
But that outputs
com.metasieve.shoppingcart.ShoppingItem : 1 , which is only a reference to some arbitrary item in the cart. I want to get back the actual name of my item.
Thanks in advance.
EDIT:
My domain class (DomainObj) is defined as follows:
class DomainObj extends com.metasieve.shoppingcart.Shoppable {
String name
static constraints = {
name blank: false
}
}
EDIT #2:
def index() {
def s = new DomainObj(name: "A Plain Ole Domain Object")
s.addToShoppingCart()
def r = new DomainObj(name: "Second Plain Ole Domain Object")
r.addToShoppingCart()
def checkedOutItems = shoppingCartService.checkOut()
println currentItems
println "-----"
checkedOutItems.each {
println it['item']
println it['qty']
}
}
The output of this is:
[com.metasieve.shoppingcart.ShoppingItem : 1, com.metasieve.shoppingcart.ShoppingItem : 2]
com.metasieve.shoppingcart.ShoppingItem : 2
1
com.metasieve.shoppingcart.ShoppingItem : 1
1
According to the documentation it["item"] gives you back the entity of a domain class that extends Shoppable. So in this case when you are printing it out it's calling the toString() method of that domain class. If you want that to return the value of the name property you need to implement your own toString(). Here is such an example
#Override
String toString() {
return name
}
EDIT:
Well as it's not clear from the documentation it['item'] is a pointer to the Shoppable instance which you can then use to query for the actual product in your cart like this:
com.metasieve.shoppingcart.Shoppable.findByShoppingItem(it['item'])
Thus the following will print out the toString() value of your products
checkedOutItems.each {
println com.metasieve.shoppingcart.Shoppable.findByShoppingItem(it['item'])
println it['qty']
}
For testing I created the following domain and controller.
Domain:
package com.test
class MyProduct extends com.metasieve.shoppingcart.Shoppable {
String name
static constraints = {
name(blank: false)
}
#Override
String toString() {
return name
}
}
Controller:
package com.test
class MyProductController {
def shoppingCartService
def index() {
def p1 = new MyProduct(name: 'one')
p1.save(flush: true, failOnError: true)
p1.addToShoppingCart()
def p2 = new MyProduct(name: 'two')
p2.save(flush: true, failOnError: true)
p2.addToShoppingCart()
def checkedOutItems = shoppingCartService.checkOut()
checkedOutItems.each {
println com.metasieve.shoppingcart.Shoppable.findByShoppingItem(it['item'])
println it['qty']
}
}
}
Update: I found the problem. I needed to save the "train" domain as follows.
train.save(flush: true)
I needed to provide a flush, as well.
I edited to include the information requested. Thanks.
I have two domain classes as follows.
class Train {
String name
static hasMany = [passengers: Person]
. . .
}
class Person {
String firstName
String lastName
. . .
}
I am trying to use a where query to look for passengers with a given first name. Here is the full integration test code. The first query, looking for the passenger, does not work. The second one, looking for the train by name, works.
I am using Grails 2.2.1 and am running the test inside of my IDE, Groovy/Grails Tool Suite 3.2. I am not bootstrapping data, but am adding data in the test. Please see the testSomething code below.
Here is the test code.
import grails.converters.*
import static org.junit.Assert.*
import org.junit.*
class TrainIntegrationTests {
#Before
void setUp() {
// Setup logic here
}
#After
void tearDown() {
// Tear down logic here
}
#Test
void testSomething() {
def person1 = new Person()
person1.firstName = "George"
person1.lastName = "Romero"
person1.save();
println "person1.id: " + person1.id
def person2 = new Person()
person2.firstName = "Jane"
person2.lastName = "Smith"
person2.save();
def train = new Train()
train.name = "This Train"
train.addToPassengers(person1)
train.addToPassengers(person2)
train.save()
// This prints out 2.
println "passengers size" + train.passengers.size()
// This does not work. No results are returned.
def query = Train.where {
passengers {
firstName == 'George'
}
}
def qResults = query.list()
// No results
println "qResults: " + qResults
// This does work. Results returned.
def query1 = Train.where {
name == 'This Train'
}
def qResults1 = query1.list()
// Returns results.
println "qResults1: " + qResults1
// Don't really care about assert results yet.
// Just looking at the print outs and seeing how this all works.
assert true
}
}
What am I missing in the passengers query?
All,
I found the problem. I needed to save with a flush, as well.
Instead of . . .
train.save()
I used . . .
train.save(flush: true)
The query began working after that.