Spring is not caching my function when i am using default key such as -
#PostMapping("getDashboardDataNew")
#Cacheable(value="myDash")
public DashboardDto getHomeDashboardDataNew(#RequestBody DashboardRequest dashboardRequest) {
LOGGER.info(" Get All the Dashboard Information : ");
//code
return dashboardDto;
}
But when I am providing custom key using sPEL its caching the response eg.
#PostMapping("getDashboardDataNew")
#Cacheable(value="myDash", key="#dashboardRequest.level")
public DashboardDto getHomeDashboardDataNew(#RequestBody DashboardRequest dashboardRequest) {
LOGGER.info(" Get All the Dashboard Information : ");
//code
return dashboardDto;
}
The request payload is always-
{"fromDate":null,"toDate":null,"theme":null,"activity":null,"level":1,"levelValue":null,"state":null,"district":null}
Even after auto generating equals and hashcode using eclipse the spring is not caching the value. Below are the auto generated codes
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((activity == null) ? 0 : activity.hashCode());
result = prime * result + ((fromDate == null) ? 0 : fromDate.hashCode());
result = prime * result + ((level == null) ? 0 : level.hashCode());
result = prime * result + ((levelValue == null) ? 0 : levelValue.hashCode());
result = prime * result + ((organizer == null) ? 0 : organizer.hashCode());
result = prime * result + ((theme == null) ? 0 : theme.hashCode());
result = prime * result + ((toDate == null) ? 0 : toDate.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DashboardRequest other = (DashboardRequest) obj;
if (activity == null) {
if (other.activity != null)
return false;
} else if (!activity.equals(other.activity))
return false;
if (fromDate == null) {
if (other.fromDate != null)
return false;
} else if (!fromDate.equals(other.fromDate))
return false;
if (level == null) {
if (other.level != null)
return false;
} else if (!level.equals(other.level))
return false;
if (levelValue == null) {
if (other.levelValue != null)
return false;
} else if (!levelValue.equals(other.levelValue))
return false;
if (organizer == null) {
if (other.organizer != null)
return false;
} else if (!organizer.equals(other.organizer))
return false;
if (theme == null) {
if (other.theme != null)
return false;
} else if (!theme.equals(other.theme))
return false;
if (toDate == null) {
if (other.toDate != null)
return false;
} else if (!toDate.equals(other.toDate))
return false;
return true;
}
I am not changing the request payload.
By default when no key is supplied, Spring cache relies on SimpleKeyGenerator which relies on hashcode of parameters to generate the key. You can check this link.
I figured out what went wrong here.
I was changing one of the property of the request payload somewhere inside the function eg.
dashboardRequest.setLevel(dashboardRequest.getLevel() + 1);
And as spring cache AOP puts the value in cache after the method execution is was using the modified object instead of value provided in param effectively making my key different from the key that would have generated by request payload. Hope this helps someone.
Related
I have a Map in Java 8.
I need to check if the list that comprises the map value is empty or null and return the result .
I have tried likewise with no luck
public boolean mapValuesEmpty() {
boolean result = true;
for (Entry<Integer, List<SomeObjectName>> entry : eventLogsMap.entrySet()) {
if (entry.getValue() != null) {
result = false;
break;
}
}
return result;
}
Many thanks
boolean result = eventLogsMap
.values()
.stream()
.anyMatch(list -> list != null && !list.isEmpty())
Example: Filter a list of products that have a price based on fromPrice and toPrice. They could either both be supplied, or just one.
Find all products whose price is greater than fromPrice
Find all products whose price is less than toPrice
Find all products whose price is between fromPrice and toPrice
Product:
public class Product {
private String id;
private Optional<BigDecimal> price;
public Product(String id, BigDecimal price) {
this.id = id;
this.price = Optional.ofNullable(price);
}
}
PricePredicate:
public class PricePredicate {
public static Predicate<? super Product> isBetween(BigDecimal fromPrice, BigDecimal toPrice) {
if (fromPrice != null && toPrice != null) {
return product -> product.getPrice().isPresent() && product.getPrice().get().compareTo(fromPrice) >= 0 &&
product.getPrice().get().compareTo(toPrice) <= 0;
}
if (fromPrice != null) {
return product -> product.getPrice().isPresent() && product.getPrice().get().compareTo(fromPrice) >= 0;
}
if (toPrice != null) {
return product -> product.getPrice().isPresent() && product.getPrice().get().compareTo(toPrice) <= 0;
}
return null;
}
}
Filters:
return this.products.stream().filter(PricePredicate.isBetween(fromPrice, null)).collect(Collectors.toList());
return this.products.stream().filter(PricePredicate.isBetween(null, toPrice)).collect(Collectors.toList());
return this.products.stream().filter(PricePredicate.isBetween(fromPrice, toPrice)).collect(Collectors.toList());
Is there a way to improve my Predicate instead of having the if not null checks? Anything that can be done with optionals?
No, Optional is not designed to replace null checks.
But your code can be improved by avoiding duplication, and by avoiding to return null (which is clearly not a valid value for a Predicate) if both arguments are null:
public static Predicate<Product> isBetween(BigDecimal fromPrice, BigDecimal toPrice) {
Predicate<Product> result = product -> true;
if (fromPrice != null) {
result = result.and(product -> product.getPrice().isPresent() && product.getPrice().get().compareTo(fromPrice) >= 0);
}
if (toPrice != null) {
result = result.and(product -> product.getPrice().isPresent() && product.getPrice().get().compareTo(toPrice) <= 0);
}
return result;
}
You can use Apache Commons Lang, it offers null safe comparison:
ObjectUtils.compare(from, to)
null is assumed to be less than a non-value
boolean isSuccess = aMap.entrySet().stream().anyMatch(entry -> {
AKey aKey= entry.getKey();
BValue bValue = bMap.get(aKey);
if (bValue == null) {
return false;
}
AValue aValue = entry.getValue();
if (compareDetail(aValue, bValue)) {
return false;
}
return true;
}
);
this code always only loop one time, how can i loop all elements then return true when two if blocks false?
It seems you need to try allMatch instead.
I have a class Person with properties id, name and age.
I would like to cache Person object using id and name.
my method is
#Cacheable(value = "person", key = "#p.id + p.name")
getPerson(Person p).
Question is, how do i use cache annotation on getPerson()... something like this.
Using the annotation you could concatenate the values to create a key (I read but have not tested tha the debug symbols may be removed and so the parameter should be referenced as "p0").
#Cacheable(value="person", key="#p0.id.concat(‘:’).concat(#p0.name)")
Otherwise, it will be cached based on Person class equals() and hashCode() just the same way as if you were using the Person object as a key in a Map.
So, for example:
public class Person {
String id;
String name;
Number age;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Person))
return false;
Person other = (Person) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
When I use the RadTreeView in ChildWindow, even though I set the IsDragDropEnabled property to "True", I can't drag the items. But when I use the RadTreeView in a UserControl, it can drag.
What is the problem, and how can I fix it?
You have to fire event
In contructor
this.treeView1.AddHandler(RadDragAndDropManager.DropQueryEvent, new EventHandler<DragDropQueryEventArgs>(OnDropQuery), true);
Then
private void OnDropQuery(object sender, DragDropQueryEventArgs e)
{
RadTreeViewItem destinationItem = e.Options.Destination as RadTreeViewItem;
object source = this.GetItemFromPayload<object>(e.Options.Payload);
object target = destinationItem != null ? destinationItem.Item : null;
DropPosition position = destinationItem != null ? destinationItem.DropPosition : DropPosition.Inside;
if (source != null && target != null)
{
Section sourceSection = source as Section;
Section targetSection = target as Section;
Question sourceQuestion = source as Question;
Question targetQuestion = target as Question;
if (sourceQuestion != null)
{
try
{
if (sourceQuestion != null && targetQuestion != null && object.ReferenceEquals(sourceQuestion, targetQuestion))
{
sourceSection.Questions.Remove(sourceQuestion);
targetSection.Questions.Add(sourceQuestion);
e.QueryResult = false;
return;
}
if (targetQuestion != null && position == DropPosition.Inside)
{
sourceSection.Questions.Remove(sourceQuestion);
targetSection.Questions.Add(sourceQuestion);
e.QueryResult = false;
return;
}
if (position != DropPosition.Inside && targetQuestion == null)
{
sourceSection.Questions.Remove(sourceQuestion);
targetSection.Questions.Add(sourceQuestion);
e.QueryResult = false;
return;
}
}
catch (Exception ex)
{
}
}
}
else
{
e.QueryResult = false;
return;
}
e.QueryResult = true;
}
This is it.