Liferay comparator not working - sorting

I am using method for finding structure articles:
List<JournalArticle> articles = JournalArticleLocalServiceUtil.getStructureArticles(groupId, "15566", 0, 10000, comparator);
comparator is instance of class:
public class OrderByEventsStartDate extends OrderByComparator{
public int compare(Object o1, Object o2){
System.out.println("comparator test");
return 1;
}
}
Message is never printed and results are not sorted... Any help, please?

results are not sorted...
Because you are always returning 1.
Now to create an OrderByComparator you need to do something more.
If you look at the source code as to how the OrderByComparator is used by the different persistence methods you would get some idea.
Also a look at some of Liferay's implemented Comparators will shed some light as to what you need to do:
Journal Comparators - You can check the ArticleTitleComparator
UserFirstNameComparator
A super-short tutorial on implementing OrderByComparator in liferay
You would require to create 3 fields:
public static final String ORDER_BY_ASC - Specifies the field with which you want to order the results. In the ascending manner.
public static final String ORDER_BY_DESC - Specifies the field with which you want to order the results. In descending order.
public static final String[] ORDER_BY_FIELDS - Specifies the different fields required for sorting (refer UserFirstNameComparator for multiple fields).
Implement the compare method on the field you would like to sort
Impement the getOrderBy() method - refer ArticleTitleComparator
Impement the getOrderByFields() method - refer ArticleTitleComparator
Impement the isAscending() method, required in compare and getOrderBy methods to decide whether it is asc or desc - refer ArticleTitleComparator
Message is never printed and
Because you have not implemented these methods, it ignores the OrderByComparator you have passed. You can check the source code of the method you are using JournalArticleLocalServiceImpl#getStructureArticles
Hope this helps.

Related

How to GroupBy objects from a list by some common catalog of properties in Java 8

I've been struggling with a problem with one of my lists of data because one of the requirements after generating it is to group some of them by some common parameters (more than 1)
What I should get at the end is a map where the value is a list of common objects. For example.
List<Cause> listToGroup = new ArrayList<>();
listToGroup.add(Similar);
listToGroup.add(Common);
listToGroup.add(Similar);
listToGroup.add(Similar);
listToGroup.add(Common);
In a weird way to represent one group (Similar) and the other (Common), those should be separated into two different lists (that list is generated by a request to other methods, in that case, I just added manually to show what could be the contained data in the list). My main problem is the criteria to group them because is based on a group of parameters that are shared, but not all (if the required parameters are equal, should belong to the same list) In the class shown below, that behaviour is seen because there are some parameters that are not being considered.
public class Cause extends GeneralDomain {
//parameters which must be equals between objects
private Long id;
private Date creationDate;
private Part origin;
private Part destination;
//parameters which are not required to be equal
private BigDecimal value
private Stage stageEvent
//omitted getters and setters
}
I've been seeing the comparator method and the groupingBy method provided in Java 8, but at the moment I just know how to perform that task considering just one parameter (for example grouping them by id) And I have no idea about how to group them using more than one parameter.
//this should be the code if the requirement would be just one parameter to groupby, but in my case are more than one.
Map<Long, List<Cause>> result = request.getList(criteria)
.stream()
.map(p -> parsin.createDto(p))
.collect(groupingBy(Cause ::getId));
I would be really glad for any suggestion. If my explanation is not clear, I'm so sorry. That became so complicated that even is hard for me to explain

Spring Sorting with Nulls_Last Handling not working

I created a sort rule like this for sorting my list:
Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"productOrder", Sort.NullHandling.NULLS_LAST), new Sort.Order(Sort.Direction.ASC,"producedYear", Sort.NullHandling.NULLS_LAST));
with this rule I want to sort the productOrder first, and then if the productOrder is the same then the producedYear will be compared and sorted. If there are null values presented, it should be sorted at the end of the list. productOrder will have type Long and producedYear will have type Double.
My Repository interface extends the JpaRepository:
public interface ProductRepository extends JpaRepository<Product, String> {
List<Product> findByDisabledAndValid(int disabled, int valid, Sort sort);
}
But the sorted list I received is containing the null values always at the beginning of the list. This means the null values will be sorted first, then come the productOrder, and finally the producedYear will be sorted. It seems that the third parameter that I defined on my Sort.Order method is not working.
Does anyone have an idea why? Thank you very much
Instead of using the Sort.NullHandling.NULLS_LAST integrated with Spring, I solved the above problem by creating my own Sort function, like this:
Collections.sort(resultList, Comparator
.comparing(Product::getProductOrder, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Product::getProducedYear, Comparator.nullsLast(Comparator.naturalOrder())));
Hope this help if someone also faces the same problem.
Regards!

Spring Data Rest - Sort by multiple properties

I have an entity as below
Class Person{
String id;
String name;
String numberOfHands;
}
With Spring Data Rest (Gosling Release Train), I'm able to specify
localhost/Person?sort=name,asc
for sorting name name ascending. Now, in a case where I need to sort by numberOfHands descending and name ascending. I'm able to specify
localhost/Person?sort=numberOfHands,name,asc
But, I'm not able to specify
localhost/Person?sort=numberOfHands,desc,name,asc
Is there a way to specify multiple sort order?
Thanks!
Solution (tl;dr)
When wanting to sort on multiple fields you simply put the sort parameter multiple times in the URI. For example your/uri?sort=name,asc&sort=numberOfHands,desc. Spring Data is then capable of constructing a Pageable object with multiple sorts.
Explanation
There is not really a defined standard on how to submit multiple values for a parameter in a URI. See Correct way to pass multiple values for same parameter name in GET request.
However there is some information in the Java Servlet Spec which hints on how Java servlet containers parse request parameters.
The getParameterValues method returns an array of String objects containing all the parameter values associated with a parameter name. ... - Java Servlet Spec, section 3.1
The sample further in that section states (although it mixes request and body data)
For example, if a request is made with a query string of a=hello and a post body of a=goodbye&a=world, the resulting parameter set would be ordered a=hello, goodbye, world.
This sample shows that when a parameter (a in the example) is presented multiple times the results will be aggregated into a String[].
Here is how to construct the multi Sort object manually/programatically.
Sort sort = Sort.by(
Sort.Order.asc("name"),
Sort.Order.desc("numberOfHands"));
return personRepository.findAll(sort);
Note: This solution does not directly solve the original question asked, but may help visitors that landed on this question while searching for a solution how to sort on multiple properties from a backend perspective / in a somewhat "hardcoded" way. (this solution does not require/take any URI parameters)
When dynamic fields are there then you simply do match with fields and add in sorting list like.
List<Sort.Order> sorts= new ArrayList<>();
if (sort == "name" && sortingOrder.equalsIgnoreCase("DESC")) {
sorts.add(new Sort.Order(Sort.Direction.DESC,"name"));
} else if (sort == "numberOfHands" && sortingOrder.equalsIgnoreCase("DESC")) {
sorts.add(new Sort.Order(Sort.Direction.DESC,"numberOfHands"));
}
return personRepository.findAll(Sort.by(sorts));
If you are using Pagination then directly add in PageRequest Request.
return personRepository.findPersons(PageRequest.of(pageNo, pageSize, Sort.by(sorts)));

Linq Group By Issue - can't get the syntax right

For some reason I am totally stuck on the syntax for LINQ Group in vb.net - can somebody help me sort out the following?
I have 5000 objects like this:
Public Class ExpressionReturn
Implements IComparable(Of ExpressionReturn)
Public Property Price As Price
Public Property Value As Nullable(Of Decimal)
Public Property Expression As Expression
Public Property Rank As Single
End Class
I am trying to group them together on price.priceid (an integer) and then return a sum of the ranks to have a series of object such as this:
Public Class RankReturn
Public Property Price As Price
Public Property Expression As Expression
Public Property RankSum As Single
End Class
I'm stuck on the syntax for Group By in Linq... can anyone help?
Thanks for coming back to me - after playing with the code with a clear head it seems a big difference between c# (which has most of the examples) and vb.net is that you seem to have to return the same objects in the select statement as are being grouped.
I've now ditched this approach as grouping is much slower than I expected - I've used a dictionary to store the sum that I need which is much quicker 5ms compared to 700ms!

Changing values of an object in a LINQ-statement

I want to add some calculated properties to an EntityObject without loosing the possibility of querying it agains the database.
I created a partial class and added the fields I need in the object. Than I wrote a static function "AttachProperties" that should somehow add some calculated values. I cannot do this on clientside, since several other functions attach some filter-conditions to the query.
The functions should look like this:
return query.Select(o =>
{
o.HasCalculatedProperties = true;
o.Value = 2;
return o;
});
In my case the calculated value depends on several lookups and is not just a simple "2". This sample works with an IEnumerable but, of course, not with an IQueryable
I first created a new class with the EntityObject as property and added the other necessary fields but now I need this extended class to be of the same basetype.
First, in my opinion changing objects in a Select() is a bad idea, because it makes something else happen (state change) than the method name suggests (projection), which is always a recipe for trouble. Linq is rooted in a functional programming (stateless) paradigm, so this kind of usage is just not expected.
But you can extend your class with methods that return a calculation result, like:
partial class EntityObject
{
public int GetValue()
{
return this.MappedProp1 * this.MappedProp2;
}
}
It is a bit hard to tell from your question whether this will work for you. If generating a calculated value involves more than a simple calculation from an object's own properties it may be better to leave your entities alone and create a services that return calculation results from an object graph.
Try something like this:
return from o in collection
select new O()
{
OtherProperty = o.OtherProperty,
HasCalculatedProperties = true,
Value = 2
};
This will create a copy of the original object with the changes you require and avoid all the messiness that come with modifying an entity in a select clause.

Resources