How to programmatically invalidate a Quarkus Cache? - caching

I´m running into a problem where using the #CacheInvalidate annotation is not enough anymore.
One method has to erase two different caches, one of them uses two of the given arguments and the other uses all three.
#CacheInvalidate(cacheName = "cache-with-two-identifiers")
#CacheInvalidate(cacheName = "cache-with-three-identifiers")
public void doSomething(#CacheKey String identifier, #CacheKey String anotherIdentifier, String aThirdIdentifier){
}
The #CacheKey annotated arguments are used for the cache with two identifiers, so I cannot annotate the third argument as well, but it would be required to match the keys of the cache-with-three-identifiers.
The only solution I see so far is programmatically clearing the third-arg-cache within the method itself. How would you do that in Quarkus?

There is currently no programmatic caching API for Quarkus.
There is already an open issue for it, you can +1 for it and provides feedback: https://github.com/quarkusio/quarkus/issues/8140

Related

How to handle optional service dependency of service in Spring Boot?

I've a service called InformationService. It optionally depends on ReleaseService. If the property external.releaseservice.url is set, the InformationService shall make a request to it and enrich it's own response with aggregate data.
If however the url is not defined, the response shall simply return a string like not available for the fields in question.
What's the spring boot way to achieve this? Inject an Optional<ReleaseService> into the InformationService? Is there another pattern for this?
You have three ways to achieve this.
#Autowired(required = false)
This works, but it requires field injection, which is not great for unit tests as is well known.
#Autowired(required = false)
private ReleaseService releaseService;
Java Optional type
As you said, Optional will also do the job and it allows you to stick to constructor injection. This is my suggested approach.
Spring's ObjectProvider
There is also an ObjectProvider designed specifically for injection points which you can use to achieve this as follows.
public InformationService(ObjectProvider<ReleaseService> releaseServiceProvider) {
this.releaseService = releaseServiceProvider.getIfAvailable();
}
It is more cumbersome and therefore I would avoid it. There is an advantage that allows you to specify a default instance if none is available but I guess that is not what you need.

Spring Cache+Redis cache doesn't calculate keys based on method/class names

I'm using redisson with a jcache abstraction, simply put I have this:
public class MyService{
#Cacheable("cacheA")
public String returnSomethingAfterLongTime(String parameter){
//...
}
#Cacheable("cacheA")
public String returnSomethingElse(String parameter){
}
}
Problem is that both of them create a redis key like "cacheA::parameter", in other words the class and method name are not taken into account.
This causes a problem if the string "parameter" is a common word because I have to be aware of every part of code where "cacheA" is used so to make sure that no inefficiency is brought up due to the fact that the "parameter" key could be replicated among calls.
Is there something that I'm doing wrong?
It looks like you can specify a "key" attribute to customize it to cache based on method name.
Spring Cacheable key attribute
There are a lot of good examples and answers on this post.
I've never personally used Spring Cache, but it looks like you can specify #Cacheable("cacheA", key="#parameter") and the value of parameter will be used as the key rather than the word "parameter".

#Cacheable with Spring 3.1

I am using #Cacheable with Spring 3.1. I little bit confused with value and key mapping parameters in Cacheable.
Here is what I am doing:
#Cacheable(value = "message", key = "#zoneMastNo")
public List<Option> getAreaNameOptionList(String local, Long zoneMastNo) {
//..code to fetch data form database..
return list;
}
#Cacheable(value = "message", key = "#areaMastNo")
public List<Option> getLocalityNameOptionList(String local, Long areaMastNo) {
//..code to fetch data form database..
return list;
}
What happening here, second method is dependent on selected value of first method,
but issue is suppose when I pass zoneMastNo = 1 and areaMastNo = 1 then second method returns first methods result.
Actually, I have lots of services hence, I am looking to use common value for cacheable for specific use cases.
Now my questions are:
How can I solve this issue?
Is it good idea that use cacheable for every services?
After specified time will cache completely remove from memory without
using #CacheEvict ?
How can I solve this issue?
I assume zoneMastNo and areaMastNo are completely different keys, by which I mean List<Option> for zoneMastNo = 1 is not the same as List<Option> for areaMastNo = 1. This means you need two caches - one keyed by zone and the other by area. However you are explicitly using only one cache named message. Quoting 29.3.1 #Cacheable annotation:
#Cacheable("books")
public Book findBook(ISBN isbn) {...}
In the snippet above, the method findBook is associated with the cache named books.
So if I understand correctly, you should basically use two different caches:
#Cacheable(value = "byZone", key = "#zoneMastNo")
public List<Option> getAreaNameOptionList(String local, Long zoneMastNo)
//...
#Cacheable(value = "byArea", key = "#areaMastNo")
public List<Option> getLocalityNameOptionList(String local, Long areaMastNo)
Also are you sure these methods won't have a different result depending on local parameter? If not, what is it used for?
Is it good idea that use cacheable for every services?
No, for the following reasons:
some methods are just fast enough
...and caching introduced some overhead on its own
some services call other services, do you need caching on every level of hierarchy
caching needs memory, a lot of it
cache invalidation is hard
After specified time will cache completely remove from memory without using #CacheEvict ?
That totally depends on your cache implementation. But every sane implementation has such an option, e.g. EhCache.
question 3:
it depends on your cache expiration configuration. if you use ehcache, change the settings in ehcache.xml.

EhCache: #CacheEvict on Multiple Objects Using Annotations

I understand that using Spring's (3.1) built in CacheManager using the EhCache implementation, there are certain limitations when in proxy mode (the default) as per this post:
Spring 3.1 #Cacheable - method still executed
Consider the scenario I have:
#CacheEvict(value = "tacos", key = "#tacoId", beforeInvocation = true)
removeTaco(String tacoId) {
// Code to remove taco
}
removeTacos(Set<String> tacoIds) {
for (String tacoId : tacoIds) {
removeTaco(tacoId);
}
}
In this repository method, calling removeTacos(tacoIds) will not actually Evict anything from the Cache because of the limitation described above. My workaround, is that on a service layer above, if I wanted to delete multiple tacos, I'd be looping through each taco Id and passing it into removeTaco(), and never using removeTacos()
However, I'm wondering if there's another way to accomplish this.
1) Is there an SpEL expression that I could pass into the key that would tell EhCache to expire every id in the Set?
e.g. #CacheEvict(value = "tacos", key = "#ids.?[*]") // I know this isn't valid, just can't find the expression.
Or is there a way I can have removeTacos() call removeTaco and actually expire the Cached objects?
The #Caching annotation can be used to combine multiple annotations of the same type such as #CacheEvict or #CachePut, this is the example from the Spring documentation
#Caching(evict = { #CacheEvict("primary"), #CacheEvict(value="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)
You can do one of two things
#CacheEvict(value = "tacos", allEntries = true)
removeTacos(Set<String> tacoIds)
which is not so bad if tacos are read a lot more than they are removed
OR
removeTacos(Set<String> tacoIds) {
for (String tacoId : tacoIds) {
getTacoService().removeTaco(tacoId);
}
}
by calling the service (proxy) you invoke the cache eviction.
AFAIK #CacheEvict supports only removing single entry (by key) or all entries in given cache, there's no way to remove at once multiple entries. If you want to put, update or remove multiple objects from cache (using annotations) and you may switch to memcached take a look at my project Simple Spring Memcached (SSM).
Self invocations don't go through the proxy so one of the solution is to switch to other mode than proxy. Anther solution (I'm not recommending it) may be keeping reference to the service in service (as an autowired field) and use it to invoke removeTaco.
Several months ago I had similar issue in one of my projects. It didn't use Spring Cache but SSM which also requires proxy. To made it work I moved caching (annotations) from service to DAO (repositories) layer. It solved problem with self invocation.

Best practice for validating a URL with Spring-MVC?

I am using Spring MVC for my web application.
I need to validate that the URL the user inputs is valid and was wondering if there is something in Spring that can do the basic checks for me (for example starts with http/https, has domain name etc).
ValidationUtils only contains very basic checks and I know I can write a regular expression in the validate() method however prefer to avoid it inm case someone has already done it :)
Thanks
In the past, I have always utilized Hibernate Validator. Simply annotate the appropriate field in your form bean with a #URL constraint.
If you've never used the ORM part of Hibernate before, don't let that scare you. The Validator portion is not dependent on the ORM stuff, and integrating it into Spring is very straightforward.
If for some reason you can't use Hibernate Validator... or you just want to stick with what you're comfortable with, a good place for regex's is RegExLib.com; several patterns that can match a URI are listed there.
Ended up using UrlValidator from apache commons.
I know this question is quite old, but I just need the same and I think I'll go with the PropertyEditors in SpringFramework.
More precisely there is URLEditor, which you can use to convert a String representation to an actual URL object.
Here is a link to the respective documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-beans-conversion
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/propertyeditors/URLEditor.html
In my case, I think about using the following code within a Spring Validator to check whether a String entered by a user is a valid URL or not:
try {
PropertyEditor urlEditor = new URLEditor();
urlEditor.setAsText(field.getValue());
} catch (IllegalArgumentException ex) {
errors.rejectValue("nameOfTheFieldToBeValidated", "url_is_invalid");
}
However, as for now, I'm unsure whether it is possible to configure which protocol is going to be accepted as valid (i.e. URLEditor seems to also accept URLs starting with "classpath:")
Use a spring interceptor:
http://java.dzone.com/articles/using-spring-interceptors-your

Resources