Sort a list based on URL parameter (or sort nested domain model in query) - list

I'm sure there is a way to do this, but I'm really stuck on this one.
I have a domain model that connects to entities Foo and Bar in a many-to-many-relationship. Now when I want to list all Foos to a certain Bar, I do the query and get a lot of FooBar objects. I iterate through these objects and add all Foos to a list.
Like so:
def fooBarRelations = FooBar.findAllByBar bar
def fooList = []
fooBarRelations.each { fooList.add it.foo }
How can I sort the fooList based upon the parameters a g:sortableColumn adds to the url namely sort (the field to sort) and order.
I know you can pass the parameters to the query directly but I think this is not possible in my case?
So how can I either
Make one query without list iterating so I can pass in the sorting parameters OR
Sort my custom list based upon the sorting parameters?
Addition 1 (03/25/2012)
If I could to this ...
def fooBarRelations = FooBar.findAllByBar bar, [sort: 'foo.' + params.sort, order: params.order]
... the problem would be solved. But passing this to the query does not have any effect on the output. Is there any way I can sort a query by a sub-property?

If you really can't sort within the query itself. Then you need a list of lists.
List<List<Fields>> mylist;// where List<Fields> is a lists of the fields.
Then use a Comparator to sort your List> by the desired filed. Say your desired field is at index 3:
new Compare(List<Fields> L1, List<Fields> L2){
if(L1.get(3)>L2.get(3))
return -1;//etc.
UPATE BASED ON COMMENT:
say your entity is as follows
public class Entity{
String name, address, school;
Integer bankaccount;
//etc...
}
Then
public class WhereISort{
List<Entity> myList;
String mysorter;//mysorter can be declared here as static final
public WhereISort(){//maybe pass list in here or whatever
}
public Response myWebService(params..., String sorter){
mysorter=sorter;//mysorter can be declared here as static final
Collections.sort(myList, new Comparator() {
public int compare(Entity e1, Entity e2) {
if(mysorter.equalsIgnoreCase("name")){
return e1.getName().compareToIgnoreCase(e1.getName());
}else if(mysorter.equalsIgnoreCase("bankaccount")){
//your code here, etc.
}
}
});
}
}
Of course, the main point is using "mysorter" and the inner class "Comparator" to sort

Related

how to pass all List<String> native methods to a List<Random>?

I'm new in Flutter(Dart) and I came across this problem. All lists of the type String naturally have the string methods like item.length, item.contains and so on. But when you create a random List type, it gets none of that. What is the recommended way of inherit all List properties to the custom one?
You probably didn't provide a list type and you can't see String methods.
void main() {
List<String> names = ['Dave', 'Ana', 'Robert'];
names.shuffle();
for(var name in names) {
print('name: $name, lenght: ${name.length}');
}
}

How does this query method work?

#Query("MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m,r,a LIMIT {limit}")
Collection<Movie> graph(#Param("limit") int limit);
For this query, it's returning "RETURN m, r, a", which is a full subgraph with 3 elements. Then why the return value of 'graph' method is a collection of "Movie" only? Where is the 'r, a' which is also returned.
I am trying to understanding the mechanism behind the scene.
It seems that you have a #RelationshipEntity defined in your class path but do not use it when defining #Relationships in the domain classes.
Sample:
#NodeEntity
class Pet {
// ...
}
#NodeEntity
class Person {
#Relationship(type = "HAS")
private List<Pet> pets;
// ...
}
#RelationshipEntity(type = "HAS")
class HasRelationship {
// ...
}
If Neo4j OGM, that acts behind the scenes of SDN, finds a relationship type, it looks for #RelationshipEntity first and if it finds them, tries to map the returned types back to the #NodeEntity. In this case OGM finds HasRelationship and wants to map it to the Person class. This fails because Person does only know of Pet and the objects get discarded.
Like my answer on GitHub.

Unit test for sort of random List<Object>

I have a class who's only task is to take a List<Object> and return a sorted List<Object>. For an example the sort method in the class works with a procedure which places the Objects randomly in the list.
Trying to do: to write the test for that sorting method (or class) which must fail if the sorting is in fact just random. That means I need to find the List<Object> order to test I assume.
Code to be tested
class RootLoggerFirstSorter {
List<LoggerConfig> sort(List<LoggerConfig> unSortedList) {
List<LoggerConfig> levelSortedList = new ArrayList<>(unSortedList);
Collections.sort(levelSortedList, new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
if (o1.getLevel().intLevel() == o2.getLevel().intLevel()) {
return 0;
} else if (o1.getLevel().intLevel() < o2.getLevel().intLevel()) {
return 1;
} else {
return -1;
}
}}
);
LinkedList<LoggerConfig> sortedList = new LinkedList<LoggerConfig>();
for(Iterator<LoggerConfig> i = levelSortedList.iterator(); i.hasNext();) {
LoggerConfig cfg = i.next();
addNextLoggerConfig(cfg, sortedList);
}
return sortedList;
}
private void addNextLoggerConfig(LoggerConfig cfg, LinkedList<LoggerConfig> sortedList) {
if(cfg.getName() == null || cfg.getName().isEmpty()) {
sortedList.addFirst(cfg);
} else {
sortedList.addLast(cfg);
}
}
}
Tried
.....
expect(item1.getLevel()).andStubReturn(Level.DEBUG);
expect(item2.getLevel()).andStubReturn(Level.ERROR);
expect(item3.getLevel()).andStubReturn(Level.INFO);
.....
//Ignore the pre req for test setup
#Test
public void testSort() {
List<LoggerConfig> unsortedList = makeUnsortedList();
EasyMock.replay(item1,item2,item3);
List<LoggerConfig> sortedList = tested.sort(unsortedList);
assertThat("First item on the list is ERROR level: ", sortedList.get(0).getLevel(), is(Level.ERROR) );
assertTrue(sortedList.get(1).getLevel().equals(Level.INFO) || sortedList.get(1).getLevel().equals(Level.INFO));
assertTrue(sortedList.get(2).getLevel().equals(Level.DEBUG) || sortedList.get(2).getLevel().equals(Level.DEBUG));
}
But this test will always pass since if looked at the index 1 and 2 only, index 0 will always contain the LoggerConfig with an empty name [set up is done that way]). So I thought Should I just unit test the compare method instead? If yes, how?
Problem The issue is that I need to test the sort method with a particular Object property which is the level of the LoggerConfig object. So the test must check the List order.
Many different aspects here:
Of course you do not need to test the built-in Collections.sort() method.
In that sense: instead, you want to test two aspects A) that you are actually calling that sort method B) that your comparator works as expected.
A) is achieved by the code you put in your own answer. Or to be precise: you only need one test case where you sort check for an expected result; after providing a specific test input to your method.
B) is achieved by writing test code that simply checks that compareTo() returns the expected result for the different input
In the end, this is about properly dissecting your logic into classes. Of course you can declare that comparator as anonymous inner class; and just verify that the sort method returns the expected result.
But when you make the comparator, say an inner class somewhere, you could write unit tests for just the comparator functionality.
Finally: your test case does not mean the goal that you stated: must fail if the sorting is in fact just random. You see, if the result of sort() is random, that it could randomly give you a correct result. Meaning: you can't expect a single test to verify "possibly random behavior". You would have to run many tests with a lot of different data, and verify that all of them pass; to achieve a certain confidence that the sort() isnt pure random.
But as said: you are not sorting. You are calling the built-in sort method which does not need to be tested.
I assumed the List<ConfigLogger> followed something like item1["", ERROR], item2["com.fwk.foo", DEBUG], item3["com.fwk.core.baa", INFO]. So in that case I needed to check that if item3 is in the position 1 and item2 is in position 3 in the list the implementation does the sort correctly. So test I needed was as follows:
#Test
public void testSort() {
List<LoggerConfig> unsortedList = makeUnsortedList();
EasyMock.replay(item1,item2,item3);
List<LoggerConfig> sortedList = tested.sort(unsortedList);
assertFalse(unsortedList.equals(sortedList));
assertTrue(sortedList.get(0).getName().isEmpty());
LoggerConfig cfg1 = sortedList.get(1);
LoggerConfig cfg2 = sortedList.get(2);
assertThat(cfg1.getLevel(), is(Level.DEBUG));
assertThat(cfg2.getLevel(), is(Level.INFO));
}
So I am accessing the item from the list and comparing if they are same as expected.
Should I just unit test the compare method instead?
No, you should not. The test may fail if you try to refactor the sort method later. You are actually trying to assert that the sorting is done probably. The compare method is just an implementation detail. You may not use the compare method to sort the list in the future.
Of course you also don't need to test the built-in sort method because you are actually testing your custom sort method. Anything inside this sort method is implementation details including the list.sort method you called. You should pretend that you don't know about it when you are writing a test.
Other than that, your sort method also contain some logic that is not related to the built-in sort method.

Want to check if object is in groovy list using .contains() or 'in'

import groovy.transform.EqualsAndHashCode;
#EqualsAndHashCode(includes="name")
class Activity {
public String name
public buildings = []
public rooms = [] as Set
Activity(name) {
this.name = name
}
}
thisActivity=new Activity("activity")
activityRegistry = []
// is false correct
activityRegistry.contains(thisActivity)
// add new item activity2
activityRegistry << new Activity("activity2")
// is true?????
activityRegistry.contains(thisActivity)
this code is pretty straight forward, I create an activityRegistry list, I compare empty list to object I created. naturally test fails. I create a new object on the fly using new that I insert into the list. I compare the list then to the first object created, which is not part of the list, and contains, or in passes. could someone shed some light on how? or why?
The AST "EqualsAndHashCode" only use 'properties' from the class. Properties, in groovy, are declared without a modifier ('public'), and getter/setter are automatically generated.
In your example, change public String name to String name.
See : What are 'properties' in Groovy?

Dropwizard /Jersey: Pass query-parameter with multiple values as List (maybe using a filter)

I have clients passing in IDs like this: /v1/path?id=1,2,3
What I have and want
I have a resource class for Dropwizard/Jersey.
I'd like to show up the query-parameter id=1,2,3 as a List parameter in my resource's GET method
// Resource class
public List<Something> getFilteredList(#QueryParam("id") List<String> ids) {
// filter the List<Something> based on a list of ids
}
Right now, the ids list contains 1 string which is "1,2,3".
What I tried
I tried a filter but the query parameters given by Jersey's
ContainerRequestContext.getUriInfo().getQueryParameters()
is immutable.
Questions
I would like to apply a filter and change any comma separated query parameters into multi-valued parameters so that the resource method gets a list instead.
Is there a way to change the existing query parameters using a Jersey filter?
What's a good way to solve this problem?
The best way I can think of is to just create a wrapper class for the list. This makes it easier to take advantage of the specified functionality of Jersey. You can see what I mean at Passing custom type query parameter.
For example
public class IdFilter {
private List<String> ids = new ArrayList<>();
public List<String> getIds() { return ids; }
public static IdFilter valueOf(String param) {
IdFilter filter = new IdFilter();
for (String id: param.split(",") {
filter.getIds().add(id);
}
}
}
getFilteredList(#QueryParam("id") IdFilter ids) {
We don't need to do anything else. Just having the static valueOf is enough for Jersey to know how to parse the query string.
3 ways to solve it:
use the generic context-parameter UriInfo , which is not very expressive
add an explicit custom type that can parse a comma-separated list
stay with #QueryParam List<String> requiring a concatenated query like ?id=1&id=2&id=3 given as URI
I would prefer the second as most-expressive, like answered already by Paul. This way you can concisely pass a single CSV like ?id=1,2,3,3 and also use a Set to ensure unique ID values, e.g. resulting in only [1, 2, 3].
Generic context-param UriInfo
One way would be to use a generic parameter #Context UriInfo to get the list in the method's body:
public List<Something> getFilteredList( #Context UriInfo uriInfo ) {
List<String> idList = uriInfo.getQueryParameters().get("id"); // before was #QueryParam("id")
System.out.println("idList: " + idList);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> idList.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See the tutorial in Java Vogue(2015): QueryParam Annotation In Jersey -
Custom type with static valueOf(String) factory-method
The other way is to design a custom type which can be constructed using a String:
class IdSet {
Set<String> values;
// a factory method, can also be named valueOf
public static IdSet fromString(String commaSeparated) {
return new HashSet( Arrays.asList( commaSeparated.split(",") ) );
}
}
public List<Something> getFilteredList(#QueryParam("id") IdSet ids) {
System.out.println("ids (Set): " + ids.values);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> ids.values.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See Jersey's JavaDocs for #QueryParam:
The type T of the annotated parameter, field or property must either:
Be a primitive type
Have a constructor that accepts a single String argument
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String))
Have a registered implementation of ParamConverterProvider that returns a ParamConverter instance capable of a "from string" conversion for the type.
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2, 3 or 4 above. The resulting collection is read-only.
Use a collection interface with multiple key-value pairs
When the calling client uses following URI pattern: /something?id=1&id=2&id=3 then JAX-RS can deserialize them to a single parameter of List<String> id having given multiple elements:
public List<Something> getFilteredList(#QueryParam("id") List<String> ids) {
System.out.println("ids : "+ids);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> ids.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See Mkyong: JAX-RS #QueryParam example where explained the multiple occurrences of orderBy in the GET query:
#QueryParam will convert the query parameter “orderBy=age&orderBy=name” into java.util.List automatically.
See also
Handling Multiple Query Parameters in Jersey
Deserializing List<Map<String, String>> QueryParam in jersey 1
Jersey, #QueryParam List<String>