////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////

The link:{api}grails/plugin/cache/Cacheable.html[Cacheable] and link:{api}grails/plugin/cache/CacheEvict.html[CacheEvict] annotations provided by the plugin have counterparts with the same names provided by Spring.

However, unlike the Spring versions, these apply AST transformations, avoiding the need to create runtime proxies.

== Service Method Caching

Given the below simple service, you can see that the `getMessage` method is configured to cache the results in the `"message"` cache.

[source,groovy]
----
package com.yourcompany

import grails.plugin.cache.*

class MessageService {

   @Cacheable('message')
   Message getMessage(String title) {
      println 'Fetching message'
      Message.findByTitle(title)
   }
}
----

By default the cache key is calculated using:

* The class name
* The method name
* The parameter names and values

In the previous example, the `title` parameter will be used as the cache key; if there were multiple parameters they would be combined into the key.

You can use a closure to dynamically define the key. For example:

[source,groovy]
----
package com.yourcompany

import grails.plugin.cache.*

class MessageService {

   @Cacheable(value = 'message', key = { title.toUpperCase() } )
   Message getMessage(String title) {
      println 'Fetching message'
      Message.findByTitle(title)
   }
}
----

The `CachePut` annotation can be used to place a value into the cache. For example:

[source,groovy]
----
package com.yourcompany

import grails.plugin.cache.*

class MessageService {

   ...

   @CachePut(value='message', key = { message.title })
   void save(Message message) {
      println "Saving message $message"
      message.save()
   }
}
----

The `save` method in the example above is configured as one that evicts elements from the cache. There is no need to clear the entire cache in this case; instead any previously cached item with the same `title` attribute will be replaced with the current `Message` instance.


Note that you could also use `CacheEvict` for the `save` method, which would remove the old cached value but not cache the current value:

[source,groovy]
----
package com.yourcompany

import grails.plugin.cache.*

class MessageService {

   ...

   @CacheEvict(value='message', key = { message.title })
   void delete(Message message) {
      println "Deleting message $message"
      message.delete()
   }
}
----

This service works with the `Message` domain class:

[source,groovy]
----
package com.yourcompany

class Message implements Serializable {

   private static final long serialVersionUID = 1

   String title
   String body

   String toString() {
      "$title: $body"
   }
}
----

Note that for in-memory cache implementations it's not required that the objects being cached implement `Serializable` but if you use an implementation that uses Java serialization (for example the Redis plugin, or the Ehcache plugin when you have configured clustered caching) you must implement `Serializable`.

To test this out, be sure to define a `"message"` cache in `grails-app/conf/application.yml` and save and retrieve `Message` instances using the service. There are `println` statements but you can also turn on SQL logging to watch the database access that's needed to retrieve instances that aren't cached yet, and you shouldn't see database access for cached values.

