Can I mix cache key types when using Spring #Cacheable? - spring

I'm basically wondering whether I can store data in a cache using different sets of arguments as keys, such as:
#Cacheable(value="myCache", key="{ #itemId, #organizationId }")
public long getValue(long itemId, long organizationId) { ... }
#Cacheable(value="myCache", key="#itemName")
public long getValue(String itemName) { ... }
#Caching(evict = {
#CacheEvict(value="myCache", key="{ #itemId, #organizationId }"),
#CacheEvict(value="myCache", key="#itemName")
})
public void evictValue(long itemId, long organizationId , String itemName) { }
Or would I need to create two separate caches for this?

Related

How to inject a service with multiples implementations with Net6

Hello i am trying to inject dependency of service with multiples implementations (multiple classes that implement the IDBActionQuery interface). I have this code in my Program.cs
builder.Services.AddTransient<IDBActionQuery<Period>, Select<Period>>();
And i have this interface:
public interface IDBActionQuery<T>
{
Task<List<T>> execute(string query, params (string name, object val)[] pars);
Task<List<T>> buildAndExecute();
}
And this is my Select class:
public class Select<T> : DBMotorBase<T>, IDBActionQuery<T>
{
private readonly IPrintExceptions exceptions;
private readonly IGetPropertiesService propertiesService;
private readonly ISQLParametersService sqlParameterService;
private readonly ISerializeService serializeService;
private readonly IDeserealizeService<T> deserealizeService;
public Select(string _connection,
IPrintExceptions _exceptions, IGetPropertiesService _propertiesService,
ISQLParametersService _sqlParameterService, ISerializeService _serializeService,
IDeserealizeService<T> _deserealizeService) : base(_connection)
{
exceptions = _exceptions;
propertiesService = _propertiesService;
sqlParameterService = _sqlParameterService;
serializeService = _serializeService;
deserealizeService = _deserealizeService;
}
private string build(string schema = "dbo")
{
...
}
public async Task<List<T>> buildAndExecute()
{
return await execute(build(),null);
}
public async Task<List<T>> execute(string query, params (string name, object val)[] pars)
{
...
}
private async Task<List<T>> processCommand(SqlConnection sql,
string query, params (string name, object val)[] pars)
{
...
}
private async Task<List<T>> processReader(SqlCommand cmd)
{
....
}
}
However i am receiving this error:
Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType:
Why is that???
The constructor of Select<T> should only contain Classes/Interfaces that can be injected. To do that, they must be registered as services like you did with Select<T>.
This is why it's throwing the Some services are not able to be constructed. It can't resolve the services you specified in the constructor. It can't create a fitting instance.
Guessing from your code, the problem is "string _connection". Try injecting "string _connection" via the e.g. IConfiguration or IOptions pattern instead. (Of course the other constructor parameters need to be registered services too!)
Something like this:
appsettings.json:
"ConnectionOptions": {
"Connection": "..."
},
Program.cs:
builder.Services.Configure<ConnectionOptions>
(builder.Configuration.GetSection(nameof(ConnectionOptions)));
Select<T>:
public Select(IOptions<ConnectionOptions> options,
IPrintExceptions exceptions,
IGetPropertiesService propertiesService,
ISQLParametersService sqlParameterService,
ISerializeService serializeService,
IDeserealizeService<T> deserealizeService)
: base(options.Connection)
{
_exceptions = exceptions;
_propertiesService = propertiesService;
_sqlParameterService = sqlParameterService;
_serializeService = serializeService;
_deserealizeService = deserealizeService;
}
If the "string _connection" property is a regular db connection string, I'd use IConfiguration instead.
Check out this question and similar ones for some detailed explanations.

Spring MVC: Refusing matched mapping

Consider a situation where we can have several mappings with the same regular expression, which should be validated programmatically (for instance against database).
(this is not a valid piece of code, I am trying just to explain what I am trying to achieve. Note the regular expressions in the url path)
// Animal controller
#GetMapping(path = "/{animal-category [a-z-]+}/{animal-name [a-z-]+}")
public void show(#PathVariable String animalCategory, #PathVariable String animalName) {
// if animalCategory is not found in database, continue with next controller
}
// Plants controller
#GetMapping(path = "/{plant-category [a-z-]+}/{plant-name [a-z-]+}")
public void show(#PathVariable String plantCategory, #PathVariable String plantName) {
// if plantCateogry is not found in database, continue with next controller - as there is no more, it should return 404
}
You can achieve this problem with a general controller method like this:
// General controller method
#GetMapping(path = "/{category [a-z-]+}/{name [a-z-]+}")
public void show(#PathVariable String category, #PathVariable String name) {
// look in database for the category
if(isAnimalCatagory) {
return showAnimal(category, name);
}
else if(isPlantCategory) }
return showPlant(category, name);
}
return "redirect:/404";
}
public void showAnimal(String animalCategory, String animalName) {
// for animal categories
}
public void showPlant(String plantCategory, String plantName) {
// for plant categories
}

Sort a list of objects based on a parameterized attribute of the object

Assuming that we have an object with the following attributes:
public class MyObject {
private String attr1;
private Integer attr2;
//...
public String getAttr1() {
return this.attr1;
}
public Integer getAttr2() {
return this.attr2;
}
}
One way of sorting a list mylist of this object, based on its attribute attr1 is:
mylist.sort(Comparator.comparing(MyObject::getAttr1));
Is it possible to use this code inside a method in a dynamic way and replace the getAttr1 part with a method that returns the getter of an attribute of the object based on its name? Something like:
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(Comparator.comparing(MyObject::getGetterByAttr(attr)));
}
The MyObject::getGetterByAttr(attr) part does not compile, I wrote it just as an example to explain my idea
I tried to implement a method with the following code new PropertyDescriptor(attr, MyObject.class).getReadMethod().invoke(new MyObject()) but It's still not possible to call a method with a parameter from the comparing method
You could add a method like
public static Function<MyObject,Object> getGetterByAttr(String s) {
switch(s) {
case "attr1": return MyObject::getAttr1;
case "attr2": return MyObject::getAttr2;
}
throw new IllegalArgumentException(s);
}
to your class, but the returned function is not suitable for Comparator.comparing, as it expects a type fulfilling U extends Comparable<? super U> and while each of String and Integer is capable of fulfilling this constraint in an individual invocation, there is no way to declare a generic return type for getGetterByAttr to allow both type and be still compatible with the declaration of comparing.
An alternative would be a factory for complete Comparators.
public static Comparator<MyObject> getComparator(String s) {
switch(s) {
case "attr1": return Comparator.comparing(MyObject::getAttr1);
case "attr2": return Comparator.comparing(MyObject::getAttr2);
}
throw new IllegalArgumentException(s);
}
to be used like
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(getComparator(attr));
}
This has the advantage that it also may support properties whose type is not Comparable and requires a custom Comparator. Also, more efficient comparators for primitive types (e.g. using comparingInt) would be possible.
You may also consider using a Map instead of switch:
private static Map<String,Comparator<MyObject>> COMPARATORS;
static {
Map<String,Comparator<MyObject>> comparators=new HashMap<>();
comparators.put("attr1", Comparator.comparing(MyObject::getAttr1));
comparators.put("attr2", Comparator.comparing(MyObject::getAttr2));
COMPARATORS = Collections.unmodifiableMap(comparators);
}
public static Comparator<MyObject> getComparator(String s) {
Comparator<MyObject> comparator = COMPARATORS.get(s);
if(comparator != null) return comparator;
throw new IllegalArgumentException(s);
}
More dynamic is only possible via Reflection, but this would complicate the code, add a lot of potential error source, with only little benefit, considering that you need only to add one line of source code for adding support for another property in either of the examples above. After all, the set of defined properties gets fixed at compile time.
You could also have a single place where this comparators would be defined:
static enum MyObjectComparator {
ATTR1("attr1", Comparator.comparing(MyObject::getAttr1));
MyObjectComparator(String attrName, Comparator<MyObject> comparator) {
this.comparator = comparator;
this.attrName = attrName;
}
private final Comparator<MyObject> comparator;
private final String attrName;
private static MyObjectComparator[] allValues = MyObjectComparator.values();
public static Comparator<MyObject> findByValue(String value) {
return Arrays.stream(allValues)
.filter(x -> x.attrName.equalsIgnoreCase(value))
.map(x -> x.comparator)
.findAny()
.orElseThrow(RuntimeException::new);
}
}
And your usage would be:
public void sortListByAttr(List<MyObject> list, String attr) {
list.sort(MyObjectComparator.findByValue(attr));
}

How to correctly use PagedResourcesAssembler from Spring Data?

I'm using Spring 4.0.0.RELEASE, Spring Data Commons 1.7.0.M1, Spring Hateoas 0.8.0.RELEASE
My resource is a simple POJO:
public class UserResource extends ResourceSupport { ... }
My resource assembler converts User objects to UserResource objects:
#Component
public class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> {
public UserResourceAssembler() {
super(UserController.class, UserResource.class);
}
#Override
public UserResource toResource(User entity) {
// map User to UserResource
}
}
Inside my UserController I want to retrieve Page<User> from my service and then convert it to PagedResources<UserResource> using PagedResourcesAssembler, like displayed here: https://stackoverflow.com/a/16794740/1321564
#RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(#PageableDefault Pageable p, PagedResourcesAssembler assembler) {
Page<User> u = service.get(p)
return assembler.toResource(u);
}
This doesn't call UserResourceAssembler and simply the contents of User are returned instead of my custom UserResource.
Returning a single resource works:
#Autowired
UserResourceAssembler assembler;
#RequestMapping(value="{id}", method=RequestMethod.GET)
UserResource getById(#PathVariable ObjectId id) throws NotFoundException {
return assembler.toResource(service.getById(id));
}
The PagedResourcesAssembler wants some generic argument, but then I can't use T toResource(T), because I don't want to convert my Page<User> to PagedResources<User>, especially because User is a POJO and no Resource.
So the question is: How does it work?
EDIT:
My WebMvcConfigurationSupport:
#Configuration
#ComponentScan
#EnableHypermediaSupport
public class WebMvcConfig extends WebMvcConfigurationSupport {
#Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(pageableResolver());
argumentResolvers.add(sortResolver());
argumentResolvers.add(pagedResourcesAssemblerArgumentResolver());
}
#Bean
public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
return new HateoasPageableHandlerMethodArgumentResolver(sortResolver());
}
#Bean
public HateoasSortHandlerMethodArgumentResolver sortResolver() {
return new HateoasSortHandlerMethodArgumentResolver();
}
#Bean
public PagedResourcesAssembler<?> pagedResourcesAssembler() {
return new PagedResourcesAssembler<Object>(pageableResolver(), null);
}
#Bean
public PagedResourcesAssemblerArgumentResolver pagedResourcesAssemblerArgumentResolver() {
return new PagedResourcesAssemblerArgumentResolver(pageableResolver(), null);
}
/* ... */
}
SOLUTION:
#Autowired
UserResourceAssembler assembler;
#RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(#PageableDefault Pageable p, PagedResourcesAssembler pagedAssembler) {
Page<User> u = service.get(p)
return pagedAssembler.toResource(u, assembler);
}
You seem to have already found out about the proper way to use but I'd like to go into some of the details here a bit for others to find as well. I went into similar detail about PagedResourceAssembler in this answer.
Representation models
Spring HATEOAS ships with a variety of base classes for representation models that make it easy to create representations equipped with links. There are three types of classes provided out of the box:
Resource - an item resource. Effectively to wrap around some DTO or entity that captures a single item and enriches it with links.
Resources - a collection resource, that can be a collection of somethings but usually are a collection of Resource instances.
PagedResources - an extension of Resources that captures additional pagination information like the number of total pages etc.
All of these classes derive from ResourceSupport, which is a basic container for Link instances.
Resource assemblers
A ResourceAssembler is now the mitigating component to convert your domain objects or DTOs into such resource instances. The important part here is, that it turns one source object into one target object.
So the PagedResourcesAssembler will take a Spring Data Page instance and transform it into a PagedResources instance by evaluating the Page and creating the necessary PageMetadata as well as the prev and next links to navigate the pages. By default - and this is probably the interesting part here - it will use a plain SimplePagedResourceAssembler (an inner class of PRA) to transform the individual elements of the page into nested Resource instances.
To allow to customize this, PRA has additional toResource(…) methods that take a delegate ResourceAssembler to process the individual items. So you end up with something like this:
class UserResource extends ResourceSupport { … }
class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { … }
And the client code now looking something like this:
PagedResourcesAssembler<User> parAssembler = … // obtain via DI
UserResourceAssembler userResourceAssembler = … // obtain via DI
Page<User> users = userRepository.findAll(new PageRequest(0, 10));
// Tell PAR to use the user assembler for individual items.
PagedResources<UserResource> pagedUserResource = parAssembler.toResource(
users, userResourceAssembler);
Outlook
As of the upcoming Spring Data Commons 1.7 RC1 (and Spring HATEOAS 0.9 transitively) the prev and next links will be generated as RFC6540 compliant URI templates to expose the pagination request parameters configured in the HandlerMethodArgumentResolvers for Pageable and Sort.
The configuration you've shown above can be simplified by annotating the config class with #EnableSpringDataWebSupport which would let you get rid off all the explicit bean declarations.
I wanted to convert list of Resources to page. but when giving it PagedResourcesAssembler it was eating up the internal links.
This will get your List paged.
public class JobExecutionInfoResource extends ResourceSupport {
private final JobExecutionInfo jobExecution;
public JobExecutionInfoResource(final JobExecutionInfo jobExecution) {
this.jobExecution = jobExecution;
add(ControllerLinkBuilder.linkTo(methodOn(JobsMonitorController.class).get(jobExecution.getId())).withSelfRel()); // add your own links.
}
public JobExecutionInfo getJobExecution() {
return jobExecution;
}
}
Paged resource Providing ResourceAssembler telling Paged resource to use it, which does nothing simply return's it back as it is already a resource list that is passed.
private final PagedResourcesAssembler<JobExecutionInfoResource> jobExecutionInfoResourcePagedResourcesAssembler;
public static final PageRequest DEFAULT_PAGE_REQUEST = new PageRequest(0, 20);
public static final ResourceAssembler<JobExecutionInfoResource, JobExecutionInfoResource> SIMPLE_ASSEMBLER = entity -> entity;
#GetMapping("/{clientCode}/{propertyCode}/summary")
public PagedResources<JobExecutionInfoResource> getJobsSummary(#PathVariable String clientCode, #PathVariable String propertyCode,
#RequestParam(required = false) String exitStatus,
#RequestParam(required = false) String jobName,
Pageable pageRequest) {
List<JobExecutionInfoResource> listOfResources = // your code to generate the list of resource;
int totalCount = 10// some code to get total count;
Link selfLink = linkTo(methodOn(JobsMonitorController.class).getJobsSummary(clientCode, propertyCode, exitStatus, jobName, DEFAULT_PAGE_REQUEST)).withSelfRel();
Page<JobExecutionInfoResource> page = new PageImpl<>(jobExecutions, pageRequest, totalCount);
return jobExecutionInfoResourcePagedResourcesAssembler.toResource(page, SIMPLE_ASSEMBLER, selfLink);
}
ALTERNATIVE WAY
Another way is use the Range HTTP header (read more in RFC 7233). You can define HTTP header this way:
Range: resources=20-41
That means, you want to get resource from 20 to 41 (including). This way allows consuments of API receive exactly defined resources.
It is just alternative way. Range is often used with another units (like bytes etc.)
RECOMMENDED WAY
If you wanna work with pagination and have really applicable API (hypermedia / HATEOAS included) then I recommend add Page and PageSize to your URL. Example:
http://host.loc/articles?Page=1&PageSize=20
Then, you can read this data in your BaseApiController and create some QueryFilter object in all your requests:
{
var requestHelper = new RequestHelper(Request);
int page = requestHelper.GetValueFromQueryString<int>("page");
int pageSize = requestHelper.GetValueFromQueryString<int>("pagesize");
var filter = new QueryFilter
{
Page = page != 0 ? page : DefaultPageNumber,
PageSize = pageSize != 0 ? pageSize : DefaultPageSize
};
return filter;
}
Your api should returns some special collection with information about number of items.
public class ApiCollection<T>
{
public ApiCollection()
{
Data = new List<T>();
}
public ApiCollection(int? totalItems, int? totalPages)
{
Data = new List<T>();
TotalItems = totalItems;
TotalPages = totalPages;
}
public IEnumerable<T> Data { get; set; }
public int? TotalItems { get; set; }
public int? TotalPages { get; set; }
}
Your model classes can inherit some class with pagination support:
public abstract class ApiEntity
{
public List<ApiLink> Links { get; set; }
}
public class ApiLink
{
public ApiLink(string rel, string href)
{
Rel = rel;
Href = href;
}
public string Href { get; set; }
public string Rel { get; set; }
}

Validating a domain object for persistence

In the system I'm currently working on, I'm following SRP (I think!) by separating the validation of domain business rules vs persistence constraints. Let's employ the overused customer example. Say a customer must have a valid zip code, street address and name to satisfy the system's business rules. Let's further say that the customer's selected user name must be unique across all customers, which I define as a persistence constraint. Please consider the following "not ready for production" pseudo code:
public interface IPersistenceValidator<T>
{
bool IsValidForPersistence(T domainObj, IList<ValidationError> validationErrors);
}
public interface IValidatable
{
bool IsValid(IList<ValidationError> validationErrors);
}
public class Customer : IValidatable
{
public bool IsValid(IList<ValidationError> validationErrors)
{
//check for business rule compliance
}
}
public class CustomerDao : IPersistenceValidator<Customer>
{
public bool IsValidForPersistence(Customer domainObj, IList<ValidationError> validationErrors)
{
//check for persistence constraint compliance (user name is unique)
}
public bool SaveCustomer(Customer customer)
{
//save customer
}
}
The classes defined above might get wired up into a service class as follows:
public class SaveCustomerService
{
private CustomerDao _customerDao;
public SaveCustomerService(CustomerDao customerDao)
{
_customerDao = customerDao;
}
public bool SaveCustomer(Customer customer)
{
IList<ValidationError> validationErrors = new List<ValidationError>();
if (customer.IsValid(validationErrors))
{
if (_customerDao.IsValidForPersistence(customer, validationErrors))
{
return _customerDao.SaveCustomer(customer);
}
else
{
return false;
}
}
else
{
return false;
}
}
}
My primary concern with this approach is that future consumers of CustomerDao must know to call IsValidForPersistence() before SaveCustomer(), otherwise invalid data gets persisted. I could create DB constraints to guard against this at the SQL levels, but that feels like a kludge.
It seems like IsValidForPersistence() should be moved into CustomerDao.SaveCustomer() but then I have to refactor the signature of SaveCustomer() to include references to the ValidationErrors class. Before I dive into that big of a refactoring, I wanted to get some feedback from others on common/preffered patterns for dealing with these issues.
Thanks
first check HERE if you want to solve your validation problem like;
public class Address {
#NotNull private String line1;
private String line2;
private String zip;
private String state;
#Length(max = 20)
#NotNull
private String country;
#Range(min = -2, max = 50, message = "Floor out of range")
public int floor;
...
}
anyway you must check username in database. You can customize your validation (like go and check DB for that is unique). Look at another links to detail.
Check hibernate validator
Check Using the Validator framework from jboss
You can read Validation In The Domain Layer partI, partII, this is not java but logic is important.

Resources