Preferable way between clean session and minimal database-access - performance

consider the following scenario: i have a bean that handles user-searches with a lot of parameters used on many pages with different urls. many users may spent a larger time with custom-searches and currently i am hitting the database to load those static lists everytime.
#ManagedBean
#ViewScoped
public class SearchBean extends DefaultBean {
private String searchPath; //seo: build a url-friendly path depending on search-parameters
private List<Currency>currencies;
private List<Country>countries;
private List<Market>markets;
private List<DrugTypes>drugTypes;
private List<Products>products;
/**
* ...15 other lists
*/
private List<ResultData>results;
#PostConstruct
public void init(){
this.currencies = Currency.getAll(); //jpa-entities
this.countries = Country.getAll();
this.markets = Markets.getAll();
this.drugTypes = DrugTypes.getAll();
this.products = Products.getAll();
}
public String search(){
this.results = ResultData.getByParameters(getSearchParams());
//
//e.g. localhost:8080/myApp/search/markets/germany/class-alpha-products/rhesus?faces-redirect=true
return searchPath;
}
public List<Currency> getCurrencies() { return currencies; }
public void setCurrencies(List<Currency> currencies) { this.currencies = currencies; }
public List<Country> getCountries() { return countries; }
public void setCountries(List<Country> countries) { this.countries = countries; }
public void setMarkets(List<Market> markets) { this.markets = markets; }
public List<Market> getMarkets() { return markets; }
public void setDrugTypes(List<DrugTypes> drugTypes) { this.drugTypes = drugTypes; }
public List<DrugTypes> getDrugTypes() { return drugTypes; }
public List<Products> getProducts() { return products; }
public void setProducts(List<Products> products) { this.products = products; }
}
what is the recommend way regarding to the headline? my small gripe is, that i see 20 jpa-queries on the console although the list-data which is build with <h:selectOneMenu> on client-side does not change on new pages but must be included on every subpage.
leave it as it is
put all those lists as session-attributes and remove them in #predestroy when user leaves.
put the whole bean as sessionbean (i already have 2 session-beans ("user" and "language" and i read that having more is not a good design)
store the list-data as a json-string in a cookie and recreate the list if the cookie exists?
other suggestions?
thanks for watching!

None of all. Caching DB entities isn't the responsibility of a front end (UI) framework. That's the responsibility of the persistence (DB) framework, which is thus JPA in your case.
JPA offers 2nd level caching possibilities. Main advantage as compared to all your proposals is that it knows precisely which entities are more queried and thus need to be cached, and when exactly to invalidate a cached entity because of an entity change. JSF as being a dumb HTML form based MVC framework which only delegates user interface events/data to business services knows nothing of this all.
See also:
How to configure L2 cache in Hibernate/JPA2?
Hibernate 5.1 User Guide - Chapter 12: Caching
EclipseLink Wiki - Examples / JPA / Caching

Related

Repository vs. DAO (again)

In general this back-story does not matter but just to explain the code below:
The server handles users and user groups. User groups are able to "discover" places - at this point in time these places are coming exclusively from the Google Places API.
Current Implementation
Currently, I have a lot of JpaRepository objects, which I call Repository, in my Service Layer. I am stressing "Repository" because in my proposed solution below, they'd be downgraded to DAOs.
However, what I do not like in my current code, and also the reason for my question here, is the amount of repositories one can find in the UserGroupService.
#Service
public class UserGroupService {
private final static Logger LOGGER = LogManager.getLogger(UserGroupService.class);
#Autowired
private UserGroupRepository userGroupRepository;
#Autowired
private UserGroupPlaceRepository userGroupPlaceRepository;
#Autowired
private PlaceRepository placeRepository;
#Autowired
private GooglePlaceRepository googlePlaceRepository;
#Autowired
private GooglePlaces googlePlaces;
public UserGroupService() {
}
#Transactional
public void discoverPlaces(Long groupId) {
final UserGroup userGroup = this.userGroupRepository.findById(groupId).orElse(null);
if (userGroup == null) {
throw new EntityNotFoundException(String.format("User group with id %s not found.", groupId));
}
List<PlacesSearchResult> allPlaces = this.googlePlaces.findPlaces(
userGroup.getLatitude(),
userGroup.getLongitude(),
userGroup.getSearchRadius());
allPlaces.forEach(googlePlaceResult -> {
GooglePlace googlePlace = this.googlePlaceRepository.findByGooglePlaceId(googlePlaceResult.placeId);
if (googlePlace != null) {
return;
}
Place place = new Place();
place.setLatitude(googlePlaceResult.geometry.location.lat);
place.setLongitude(googlePlaceResult.geometry.location.lng);
place.setPlaceType(Place.PlaceType.GOOGLE_PLACE);
place.setName(googlePlaceResult.name);
place.setVicinity(googlePlaceResult.vicinity);
place = this.placeRepository.save(place);
UserGroupPlace.UserGroupPlaceId userGroupPlaceId = new UserGroupPlace.UserGroupPlaceId();
userGroupPlaceId.setUserGroup(userGroup);
userGroupPlaceId.setPlace(place);
UserGroupPlace userGroupPlace = new UserGroupPlace();
userGroupPlace.setUserGroupPlaceId(userGroupPlaceId);
this.userGroupPlaceRepository.save(userGroupPlace);
googlePlace = new GooglePlace();
googlePlace.setPlace(place);
googlePlace.setGooglePlaceId(googlePlaceResult.placeId);
this.googlePlaceRepository.save(googlePlace);
});
}
}
A Solution That Does Not Work
What could make this code a lot simpler and had the potential to resolve this mess up there, would be #Inheritance:
#Entity
#Table(name = "place")
#Inheritance(strategy InheritanceType.JOINED)
public class Place { /* .. */ }
#Entity
#Table(name = "google_place")
public class GooglePlace extends Place { /* .. */ }
However, this is not an option because then I cannot have a PlaceRepository which saves just a place. Hibernate does not seem to like it..
My proposal
I think my confusion starts with the names that Spring is using. E.g. JpaRepository - I am not so sure if this is actually "the right" name. Because as far as I understood, these objects actually work like data access objects (DAOs). I think it should actually look something like this:
public interface PlaceDao extends JpaRepository<Place, Long> {
}
public interface GooglePlaceDao extends JpaRepository<Place, Long> {
}
#Repository
public class GooglePlaceRepository {
#Autowired
private PlaceDao placeDao;
#Autowired
private GooglePlaceDao googlePlaceDao;
public List<GooglePlace> findByGroupId(Long groupId) {
// ..
}
public void save(GooglePlace googlePlace) {
// ..
}
public void saveAll(List<GooglePlace> googlePlaces) {
// ..
}
}
#Service
public class UserGroupService {
#Autowired
private GooglePlaceRepository googlePlaceRepository;
#Autowired
private UserGroupRepository userGroupRepository;
#Transactional
public void discoverPlaces(Long groupId) {
final UserGroup userGroup = this.userGroupRepository.findById(groupId).orElse(null)
.orElseThrow(throw new EntityNotFoundException(String.format("User group with id %s not found.", groupId)));
List<PlacesSearchResult> fetched = this.googlePlaces.findPlaces(
userGroup.getLatitude(),
userGroup.getLongitude(),
userGroup.getSearchRadius());
// Either do the mapping here or let GooglePlaces return
// List<GooglePlace> instead of List<PlacesSearchResult>
List<GooglePlace> places = fetched.stream().map(googlePlaceResult -> {
GooglePlace googlePlace = this.googlePlaceRepository.findByGooglePlaceId(googlePlaceResult.placeId);
if (googlePlace != null) {
return googlePlace;
}
Place place = new Place();
place.setLatitude(googlePlaceResult.geometry.location.lat);
place.setLongitude(googlePlaceResult.geometry.location.lng);
place.setPlaceType(Place.PlaceType.GOOGLE_PLACE);
place.setName(googlePlaceResult.name);
place.setVicinity(googlePlaceResult.vicinity);
googlePlace = new GooglePlace();
googlePlace.setPlace(place);
googlePlace.setGooglePlaceId(googlePlaceResult.placeId);
return googlePlace;
}).collect(Collectors.toList());
this.googlePlaceRepository.saveAll(places);
// Add places to group..
}
}
Summary
I would like to know what I don't see. Am I fighting the framework, or does my data model not make sense and this is why I find myself struggling with this? Or am I still having issues on how the two patterns "Repository" and "DAO" are supposed to be used?
How would one implement this?
I would say you are correct that there are too many repository dependencies in your service. Personally, I try to keep the number of #Autowired dependencies to a minimum and I try to use a repository only in one service and expose its higher level functionality via that service. At our company we call that data sovereignty (in German: Datenhoheit) and its purpose is to ensure that there is only one place in the application where those entities are modified.
From what I understand from your code I would introduce a PlacesService which has all the Dependencies to the PlaceRepository, GooglePlaceRepository and GooglePlaces. If you feel like Service is not the right name you could also call it the PlacesDao, mark it with a Spring #Component annotation and inject all the Repositories, which are by definition collections of things
#Component
public class PlacesDao {
#Autowired
private PlaceRepository placeRepository;
#Autowired
private GooglePlaceRepository googlePlaceRepository;
This service/DAO could offer an API findPlacesForGroup(userGroup) and createNewPlace(...) and thus making your for Loop smaller and more elegant.
On a side note: you can merge your first four lines into just one. Java Optionals support a orElseThrow() method:
UserGroup userGroup = userGroupRepository.findById(groupId).orElseThrow(() ->
new EntityNotFoundException(String.format("User group with id %s not found.", groupId));
I think the foreach does not look like a good approach to me. You're doing way to much for just a single responsibility of a function. I would refactor this to a standart for loop.
Place place = new Place();
place.setLatitude(googlePlaceResult.geometry.location.lat);
place.setLongitude(googlePlaceResult.geometry.location.lng);
place.setPlaceType(Place.PlaceType.GOOGLE_PLACE);
place.setName(googlePlaceResult.name);
place.setVicinity(googlePlaceResult.vicinity);
place = this.placeRepository.save(place);
This part can easily be a method in a service.
UserGroupPlace.UserGroupPlaceId userGroupPlaceId = new
UserGroupPlace.UserGroupPlaceId();
userGroupPlaceId.setUserGroup(userGroup);
userGroupPlaceId.setPlace(place);
UserGroupPlace userGroupPlace = new UserGroupPlace();
userGroupPlace.setUserGroupPlaceId(userGroupPlaceId);
this.userGroupPlaceRepository.save(userGroupPlace);
That part as well.
googlePlace = new GooglePlace();
googlePlace.setPlace(place);
googlePlace.setGooglePlaceId(googlePlaceResult.placeId);
this.googlePlaceRepository.save(googlePlace);
And this part: I don't understand why your doing this. You could just update the googlePlace instance you loaded from the repo. Hibernate/Transactions are doing the rest for you.

Transportation layer that support Polymorphism and Generics

I am looking for transportation layer for gwt. I would like to create ajax request using generic method, f.e this is my DAO/service:
public class GenericDao<T extends GenericModel<T>> {
private Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());
#Transient protected Class<T> entityClass;
public GenericDao() {
super();
}
public GenericDao(Class<? extends GenericModel<T>> clazz) {
this.entityClass = (Class<T>) clazz;
}
public T getBy(Long id) {
return JPA.em().find(entityClass, id);
}
public List<GenericModel<T>> get() {
logger.error("trying to get data from db");
return getList();
}
public List<GenericModel<T>> getList() {
return JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
}
public void save(GenericModel<T> entityClass) {
JPA.em().getTransaction().begin();
JPA.em().persist(entityClass);
JPA.em().getTransaction().commit();
}
public void update(T entityClass) {
JPA.em().getTransaction().begin();
JPA.em().merge(entityClass);
JPA.em().getTransaction().commit();
}
public void delete(T entityClass) {
JPA.em().getTransaction().begin();
JPA.em().remove(entityClass);
JPA.em().getTransaction().commit();
}
}
GenericModel/Entity:
#MappedSuperclass
public class GenericModel<T extends GenericModel<T>> implements Identifiable, Versionable {
#Transient
protected Class<T> entityClass;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Version
private Integer version;
// setter & getter
#Override
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
#Override
public Integer getVersion() {return version;}
public void setVersion(Integer version) {this.version = version;}
// constructor
public GenericModel() {
Class<?> obtainedClass = getClass();
Type genericSuperclass = null;
for (;;) {
genericSuperclass = obtainedClass.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
break;
}
obtainedClass = obtainedClass.getSuperclass();
}
ParameterizedType genericSuperclass_ = (ParameterizedType) genericSuperclass;
try {
entityClass = ((Class) ((Class) genericSuperclass_
.getActualTypeArguments()[0]));
} catch (ClassCastException e) {
entityClass = guessEntityClassFromTypeParametersClassTypedArgument();
}
}
public GenericModel(Long id) {
this();
this.id = id;
}
}
I am looking for mechanism that will allow me to use this generic service for all models on client side (each db entity have id- so I would like to downloads using ajax all my Entities this way, so I should have only one generic method for that on client side).
I've already checked:
GWT-RPC
RequestFactory
RestyGWT
But none of them support this feature.
I've found here:
https://www.mail-archive.com/google-web-toolkit#googlegroups.com/msg100095.html
information that: gwt-jackson supports generics and polymorphism. Unfortunately I didn't found any working example that. Can someone help, give an example, approved that information?
All entities have id and version parameter. So I would like to have one metod on client side RF that will allow me to get from server(service/dao/whatever) that entity by id- like this: Request getBy(Long id); But unfortunatelly I can't make it work. I like the RF way, so I've tried it first. Generally I don't wonna repeat code for downloading entity/proxy by id.
For better understanding, please look also on:
RequestFactory client-side inheritance of typed class with generics
I'm confused as to why you think RPC can't handle generics - according to your link, it can, but RestyGWT cannot. Granted, none of your JPA references make any sense in GWT, but those would live in a DAO on the server, not in the entity/model class themselves, or at least not in the client version. If you had a RPC method that returned T where <T extends GenericModel<T>>, then you would have serializers for every possible GenericModel<?> subtype, and any/all that are gwt-compatible could be sent over the wire.
Edit from update to question:
Your GenericModel class uses features of Java that cannot work in GWT, such as reflection. This cannot be compiled to GWT, since the compiler relies on removing reflection information to minimize your compiled size - leaving in general reflection information means leaving in details about all classes and members, even ones that it can't statically prove are in use, since some reflection might make use of them.
If there is a way to phrase your model object in a way that just deals with the data at hand, focus on that. Otherwise consider a DTO which is just the data to send over the wire - I'm not sure how you would plan to use the entityClass field on the client, or why that would be important to read from the superclass's generics instead of just using getClass().
RequestFactory will have a hard time dealing with generics - unlike RPC (and possibly RestyGWT) it cannot handle polymorphism the way you want, but will instead only send the fields for the declared type, not any arbitrary subtype. RPC will actually send the instance if it is something that the client can handle.

Retrieving data context changes with Spring Data JPA

In my application, I need to retrieve the lists of new, updated and removed entities per each transaction. Like this:
// useful functionality
#Transactional
public void createNewBlogPost(int userId, String title, String text) {
Post post = new Post();
post.title = title; // "hello"
post.text = text; // "there"
postRepository.save(post);
// more work with JPA repositories here
}
...
// gets called right after createNewBlogPost()
public void onTransaction(UnitOfWork uow) {
List<?> newEntities = uow.getNewEntities();
assertEquals(1, newEntities.size()); // 1 new entity
Object firstNewEntity = newEntities.get(0);
assertTrue(firstNewEntity instanceof Post); // this new entity
// is a Post
Post newPost = (Post)firstNewEntity;
assertEquals("hello", newPost.title);
assertEquals("there", newPost.text);
}
The most relevant thing I managed to find was an audit functionality that Spring provides with annotations like #CreatedBy, #CreatedDate, #LastModifiedBy, #LastModifiedDate. Though it's technically very close, yet it's not exactly what I want to achieve.
Does Spring Data JPA provide a mechanism to retrieve data changes per every single transaction?
Since your use case is Hibernate and JPA specific, you should take a look at Hibernate Envers and Spring Data Envers. They might give you some ideas, but be careful re: the projects themselves, I'm not sure if they're active.
I've spent some time for the research and managed to find a relatively straightforward Hibernate-specific solution. There are basically 2 problems to resolve:
Intercept data change events.
Do it on a per-request basis.
To address p.1, one can use EventListenerRegistry. Here's an example:
#Component
public class HibernateListenersConfigurer {
#Autowired
private EntityManagerFactory entityManagerFactory;
#Autowired
private HibernateListeners hibernateListeners;
#PostConstruct
public void init() {
HibernateEntityManagerFactory hibernateEntityManagerFactory =
(HibernateEntityManagerFactory)entityManagerFactory;
SessionFactoryImpl sessionFactoryImpl =
(SessionFactoryImpl)hibernateEntityManagerFactory.getSessionFactory();
EventListenerRegistry eventListenerRegistry = sessionFactoryImpl.
getServiceRegistry().
getService(EventListenerRegistry.class);
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, hibernateListeners);
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, hibernateListeners);
eventListenerRegistry.appendListeners(EventType.PRE_DELETE, hibernateListeners);
}
}
hibernateListeners object gets all these events and can do whatever required to audit them. Here's an example:
#Component
public class HibernateListeners implements
PreInsertEventListener,
PreUpdateEventListener,
PreDeleteEventListener {
#Autowired
private ChangeTracker changeTracker;
#Override
public boolean onPreInsert(PreInsertEvent event) {
// event has a bunch of relevant details
changeTracker.trackChange(event);
return false;
}
...other listeners here...
Then, to address p.2, changeTracker seen above is a request-scoped bean:
#Component
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ChangeTracker {
// a sort of "Unit of Work"
private List<Change> changes = new ArrayList<Change>();
public void trackChange(PreInsertEvent event) {
changes.add(makeChangeFromEvent(event));
}
public void handleChanges() {
// Do whatever needed :-)
}
}
Then, there are few options available to finally call handleChanges() once request processing is complete: call it manually, use HandlerInterceptor, use filter, use AOP. HandlerInterceptors and filters, are not as great, because in my case they were getting called after response has already been sent to the client, this caused inconsistency between "business data" and "changes data". I eventually switched to AOP and it seems to work just fine.
Here's a playground: https://github.com/loki2302/spring-change-tracking-experiment

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