Spring dynamically select #JsonView with pagination - spring

I want to select the Json View applied to my data depending on an URL parameter. I am trying to implement this using #JsonView annotations, and I tried some solutions (1, 2). The thing is that those solutions are basen on the controller action returning a MappingJacksonValue, but I cannot use that because I am using pagination.
My action:
public ResponseEntity<Page<MyEntity>> findAll(
int viewMode,
Pageable pageable) {
result = service.findAll(pageable);
// Here I would like to apply a Json View to the result set depending
// on the variable viewMode
return new ResponseEntity<Page<MyEntity>>(
/* Resultset with the selected view applied, and paginated */,
HttpStatus.OK
);
}

To make #JsonView work with pagination, you need to set the following property to true in application.properties:
spring.jackson.mapper.DEFAULT_VIEW_INCLUSION = true
This will cause the mapper to also serialize properties which are not annotated, enabling paging to work.

Related

How to update the content inside of Page object from Spring Data without changing the other properties

after querying from the database using the given getAll(Pageable pageable) method from spring data jpa i become an Page object. What I am doing is modifing the content list inside of this Page object but I am getting stuck here is that I dont know how to set it back to the Page object because Page doesn't have setter method, something like page.setContent(newContent), it has only getter.
Can anyone give me some hints how to set the new content to the Page object without changing the other current properties inside of it?
You need to use PageImpl(List content, Pageable pageable, long total) as example below :
//get paged data
Page<Groups> groups = groupsRepository.
findPagedGroups(pageable, lowerCase(name), lowerCase(description));
// update list
List<Groups> groupsList = groups.stream().collect(Collectors.toList());
for (Groups group : groupsList) {
group.setSize(usersGroupsRepository.countActiveUsersGroupsForGroupId(group.getId()));
}
// return new PageImpl
return new PageImpl<>(groupsList, pageable, groups.getTotalElements());

how to pass value dynamically to spring top function

Actually, I wanted to retrieve the Top 500 records in a table. I knew spring data has internal method findTop500 method for it. My question is can this 500 be passed dynamically? Suppose if my requirement changes to get Top1000 I don't want it to modify again.
Assuming you are asking about Spring data-methods
You can use a Pageable object to dynamically set how many entries you want to retrieve.
You can use it like this:
PageRequest pageRequest = new PageRequest(0, maxResults);
List<Record> records = repository.findAll(pageRequest);
List<Record> records = repository.findAllByKey(key, pageRequest);

Spring boot + JPA(Hibernate) Edit partial entity fields

all.
I have following simple form in which I want to edit the entity. The problem is that I have some fields which I don't want to be edited. For example (Image file path).
As it is now, I have the service method -
public void addOrModifyLayout(Layout layout){
if(layout.getId() == null){
layoutRepository.save(layout);
}
else {
Layout modifiedLayout = new Layout();
modifiedLayout.setId(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);
}
}
As you can see, every field that I want to be able to be edited, I should explicitly put it in the service. Can I use some mapper or trick to update only some fields that are in the view (form) ? How you handle this kind of issues?
You can either
store all the entity fields in hidden inputs (e.g. imageFilePath hidden input). So you can store on UI all the entity fields and get them back to assign to the entity.
OR
Avoid new entity creation but retrieve existing one and fill only necessary fields.
Layout modifiedLayout = layoutRepository.getById(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);

Group toghether Node properties and return as a view in Cypher

I am working with v2.2.3 of Neo4J and Spring Neo4j Data SDN 4
I want to return a few properties of a node using a cypher query and map them into attributes of a POJO.My function in Spring data repository looks something like this
#Query(
"MATCH(n:ServiceProvider{profileStatus:{pStatus},currentResidenceState:{location}}) RETURN n.name,n.currentResidenceAddress ,n.employmentStatus,"
+ "n.idProofType,n.idProofNumber
ORDER BY n.registrationDate DESC SKIP{skip} LIMIT {limit}")
List<AdminSearchMapResult> getServiceProviderRecords(
#Param("pStatus")String pStatus,
#Param("location")String location,
#Param("skip") int skip,#Param("limit")int limit);
I get an error like
Scalar response queries must only return one column. Make sure your cypher query only returns one item.
I think its because of the fact that I cant bundle all the returned attributes into a view that can map into the POJO
If I return the node itself and map it into a POJO it works
Kindly guide
This can be done using #QueryResult
Annotate the AdminSearchMapResult POJO with #QueryResult. For example:
#QueryResult
public class AdminSearchMapResult {
String name;
String currentResidenceAddress;
...
}
Optionally annotate properties with #Property(name = "n.idProofType") if the alias is different from the field name.

Enforce ordering of OData items even when $top is used

I have a DbSet<Items> collection.
The primary key is a Guid. I don't want to order by this primary key. I want to order by an editable decimal property named "Order".
The code I have is very simple, and it works great until the user puts a "$top" parameter into the request:
public class ItemsController : ApiController
{
protected DbContext ctx = // ...
// GET api/documents
[EnableQuery()]
public IQueryable<Item> Get()
{
return ctx.Items.OrderBy(o => o.Order).AsQueryable();
}
When the user puts "$top" into the query string, the order gets all messed up (it presumably forces the ordering to be done by the primary key, for consistent paging results -- however, in my situation, this is having the opposite effect, it's preventing me from having consistent paging results).
I've tried moving .AsQueryable() to be earlier in the query (before the .OrderBy(...) clause), I've tried it without the .AsQueryable(), I've tried it with two AsQueryables, etc.
There are going to be a lot of items in this table, so it needs to be done via an IQueryable (enumerating all of the items on the web server via IEnumerable is not an option here).
The only thing that has worked so far is passing in "$orderby=Order" from the client, but I don't want to force that (seems like it will get forgotten easily).
1.) Is there anything I can do to make ordering by my Order property the default behavior here?
2.) Or failing that, is there anyway to trick WebApi / OData into thinking that a custom "$orderby=Order" clause was specified?
To override default sort order, you need to set property EnsureStableOrdering of EnableQueryAttribute to false, like describe here:
A true value indicates the original query should be modified when
necessary to guarantee a stable sort order. A false value indicates
the sort order can be considered stable without modifying the query.
Query providers that ensure a stable sort order should set this value
to false. The default value is true.
So in your code, changes the action attribute like this:
// GET api/documents
[EnableQuery(EnsureStableOrdering = false)]
public IQueryable<Item> Get()
{
return ctx.Items.OrderBy(o => o.Order).AsQueryable();
}
You can manually invoke the odata in your controller. This should create the proper sorted IQueryable and then apply the $top and any other odata like $filter and $skip. Now you don't have to return an IQueryable which was causing the problem because the actual query was being executed later in the pipeline.
public class ItemsController : ApiController
{
protected DbContext ctx = // ...
public IEnumerable<Item> Get(ODataQueryOptions<Item> odata)
{
var collection = ctx.Items.OrderBy(o => o.Order);
if (odata == null)
{
//return a default max size of 100
return collection.Take(100).ToList();
}
var results = odata.ApplyTo(collection.AsQueryable()) as List<Item>;
//still provide a max incase the $top wasn't specified.
//you could check the odata to see if $top is there or not.
return results.Take(100);
}
}
More information can be found in the WebApi documentation.

Resources