Implementation of Comparable not sorting List - java

I'm having trouble getting my objects to sort.
Some initial knowledge:
I'm using MongoDB to store my collection, I'm able to retrieve them and get everything back correctly.
I have a class that implements Comparable, with a compareTo function, but I also want to be able to sort on different properties, thus I've added static comparables for each property I want to sort on.
public class PlaceHolder implements Comparable<PlaceHolder>{
private String name;
private String icon;
private String originalLangcode;
//Getters and setters + constructors here, these work 100%.
#Override
public int compareTo(PlaceHolder ph) {
return this.getName().compareTo(ph.getName());
}
public static Comparator<PlaceHolder> nameComparator = new Comparator<PlaceHolder>() {
#Override
public int compare(PlaceHolder ph1, PlaceHolder ph2) {
return ph1.getName().compareTo(ph2.getName());
}
};
public static Comparator<PlaceHolder> iconComparator = new Comparator<PlaceHolder>() {
#Override
public int compare(PlaceHolder ph1, PlaceHolder ph2) {
return ph1.getIcon().compareTo(ph2.getIcon());
}
};
public static Comparator<PlaceHolder> nativeLangComparator = new Comparator<PlaceHolder>() {
#Override
public int compare(PlaceHolder ph1, PlaceHolder ph2) {
return ph1.getNativeLang().compareTo(ph2.getNativeLang());
}
};
}
I've then wrote a function that gets all placeholders from my mongodb, returning them in a list with PlaceHolder objects.
public List<PlaceHolder> getAllPlaceholders(String sortType) {
List<PlaceHolder> list = getPlaceholderList();
switch(sortType) {
case "name":
Collections.sort(list, PlaceHolder.nameComparator);
break;
case "icon":
Collections.sort(list, PlaceHolder.iconComparator);
break;
case "native":
Collections.sort(list, PlaceHolder.nativeLangComparator);
break;
default:
Collections.sort(list, PlaceHolder.nameComparator);
break;
}
return list;
}
I always get my data unsorted:
{ "_id" : { "$oid" : "56653f82972552a4024814a3"} , "name" : "testHolder" , "icon" : "archive" , "originalLangcode" : "ENG"}
{ "_id" : { "$oid" : "5665427a97253f798067c57b"} , "name" : "doItHolder" , "icon" : "car" , "originalLangcode" : "ENG"}
{ "_id" : { "$oid" : "566545dd9725050a53b4a5a8"} , "name" : "testableHolder" , "icon" : "adjust" , "originalLangcode" : "ENG"}
{ "_id" : { "$oid" : "5665479b972511264f55aae1"} , "name" : "dataHolder" , "icon" : "hdd-o" , "originalLangcode" : "ENG"}
I'm failing to see what goes wrong.
I've debugged the comparables, and they seem to work, returning negatives and positives. But the list just doesnt seem to get sorted.
I'm using getAllPlaceholders in my controller, passing it to my Page handler which in turn generates html for a table view.
public class PlaceHolderControllerF extends ControllerAbF {
#Autowired PlaceHolderRepo pr;
#RequestMapping(value = "placeholderlist", method = RequestMethod.GET)
#ResponseBody
public String editLanguage(HttpSession httpSession) {
if (getUser(httpSession) == null) {
return noPermission();
}
return Pages.getPlaceHolderList(pr.getAllPlaceholders("name"));
}
Pages just gets my index html, passes some variables to it that then runs through my templater which fills in the variables into the html.

Related

Spring Data MongoDB support for inheritance on a nested object

So My problem is related to how spring handles inheritance when it comes to fields.
I have four classes
#Document(collection = "A")
public class A {
#Id
id;
#Field
B data;
}
public class B {
Type type
}
public class C extends B {
String cField;
public C() {
super(Type.C);
}
}
public class D extends B {
Integer dField;
public D() {
super(Type.D);
}
}
I'm able to store data into mongodb using this schema and it looks something like this
{
"_id" : ObjectId("5f291f861020d19a3db05123"),
"data" : {
"cField" : "abcd",
"type" : "C",
"_class" : "com.example.C"
},
"_class" : "com.example.A"
}
{
"_id" : ObjectId("5f291f861020d19a3db05124"),
"data" : {
"dField" : NumberInt(30),
"type" : "D",
"_class" : "com.example.D"
},
"_class" : "com.example.A"
}
Now when I try to do a findAll on repository, it does not casts to the child class, but simply returns an instance of B.
What changes do I need to make so that I can get correct child object when getting from db?

MongoDB query with $exists and $elemMatch doesn't work

E.g. I have Java objects:
public class Foo {
private Example example;
}
public class Example {
private String str1;
private String str2;
}
Field example can be null.
I need to get all Foo objects where str1 contains e.g. "text". According to documentation I tried:
#Query(value = "{ 'example' : { $exists : true, $elemMatch : { str1 : { $regex: '.*?0.*'} } } }")
but it returns empty Page.
Define the query in the repository:
#Repository
public interface FooRepo extends MongoRepository<Foo, String> {
#Query("{ 'example' : { $exists : true }, 'example.str1' : { $regex: ?0 } }")
List<Foo> findByExamplePropertyRegex(String regexStr);
}
Sample four documents in foo collection:
{ "example" : { "str1" : "apple", "str2" : "rose" } },
{ "example" : { "str1" : "pineapple", "str2" : "jasmine" } },
{ "other": "stuff" },
{ "example" : null }
Run the query from Spring Boot application using CommandLineRunner:
#Autowired
private FooRepo repo;
// ...
public void run(String... strings) throws Exception {
String regexStr = "apple"; // -or- "in"
List<Foo> list = repo.findByExamplePropertyRegex(regexStr);
list.forEach(System.out::println);
The output will be two documents with the regexStr is "apple", and one document with input "in".
Also, see: $regex operator.

How to do 3 way filtering/Grouping on Java streams

I have a Java list representation like below
List representation of data
[
{ "type" : "Error", "name" : "xyz" },
{ "type" : "Success", "name" : "abc" },
{ "type" : "none", "name" : "prq" },
{ "type" : "Success", "name" : "" },
{ "type" : "Success", "name" : "xyz" },
{ "type" : "Warning", "name" : "efc" }
.
.
.
]
(Partial representation here).
and an Object representation below
public Node {
List<String> errorNames;
List<String> SuccessNames;
List<String> WarningNames;
}
I want to use Java streams to separate the three type of names based on their type and add each name to the respective Lists.
What will be the best way (Stream.filter/Collect/Map anything else) to split the list such that at the end "Node's->(all the lists)" will have corresponding data?
Assuming your Node class actually looks something like this:
public class Node {
private String type;
private String name;
public Node(String type, String name) {
this.type = type;
this.name = name;
}
public String getType() {
return type;
}
public String getName() {
return name;
}
}
You can use Collectors#groupingBy in combination with Collectors#mapping to create a Map<String, List<String>> where they key is the type and the value are the List of name for every Node of that type:
var nodes = List.of(
new Node("Error", "xyz"), new Node("Success", "abc"),
new Node("none", "prq"), new Node("Success", ""),
new Node("Success", "xyz"), new Node("Warning", "efc")
);
var map = nodes.stream()
.collect(Collectors.groupingBy(Node::getType,
Collectors.mapping(Node::getName, Collectors.toList())));
System.out.println(map);
Output:
{Warning=[efc], Error=[xyz], none=[prq], Success=[abc, , xyz]}

generic class dynamic initialization(with spring RestTemplate)

I am currently common api client util using spring rest template.
Our api result like following..
single result :
{
"data" : {
"id" : "...",
"name" : "..."
...
}
}
multiple result :
{
"data" : {
"cnt" : 30,
"list" : [
{
"id" : "...",
"name" : "..."
...
},
{
"id" : "...",
"name" : "..."
...
},
{
"id" : "...",
"name" : "..."
...
}
...
]
}
}
And I made two common response class like following
public class Response<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
and
public class ListResponse<T> {
private long cnt;
private List<T> list;
public long getCnt() {
return cnt;
}
public void setCnt(long cnt) {
this.cnt = cnt;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
and example of using RestTemplate is
public <T> T apiCaller(String api){
T result= restTemplate.exchange(api,
HttpMethod.GET,
new HttpEntity<>(headers),
new ParameterizedTypeReference<Response<T>>(){}).getBody().getData();
return result;
}
and then I used,
when the result is single,
UserResponse user = apiRequest.<UserResponse>apiCaller("/users/1");
when the result is multiple,
ListResponse<UserResposne> users = apiRequest.<ListResponse<UserResponse>>apiCaller("/users");
But it also doesn't work.
it occur java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.joont.Response.ListResponse.
So I searched so much in google, but I didn't search how...
How can I solve this problem?
and I did it wrong? is it impossible?

Convert JSON from serializeArray() to Java class with GSON

I'm having a little trouble trying to convert a JSON string from a serialized HTML form to a Java class using Gson.
Here's the example JSON:
[
{ "name" : "ObjectClass", "value" : "Obama" },
{ "name" : "ObjectType", "value" : "Person" },
{ "name" : "Att_1_name", "value" : "Age" },
{ "name" : "Att_1_value", "value" : "52" },
{ "name" : "Att_2_name", "value" : "Race" },
{ "name" : "Att_2_name", "value" : "African American" }
]
As you can see, it passes an array, then each element of that array consists of a name and a value.
I'm somewhat lost on how to set up my Java class so that Gson can convert it. It should also be noted that the number of elements in the array is variable (there can be as many attributes as the user desires).
My (incorrect) attempt at the class was:
package com.test.objectclasses;
import java.util.ArrayList;
public class tempJSON {
ArrayList<innerJSON> inJSON;
public ArrayList<innerJSON> getInJSON() {
return inJSON;
}
public void setInJSON(ArrayList<innerJSON> inJSON) {
this.inJSON = inJSON;
}
public class innerJSON {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
Any idea how to approach this, or am I thinking about it all wrong? Thanks in advance.
First of all, follow Java naming conventions. Your class names should start with a capital letter. So upper camel case.
Get rid of your enclosing class, tempJSON and use a type token in the Gson#fromJson(..) to mark it as a List, since you have a JSON array.
List<innerJSON> innerJSONs = gson.fromJson(yourStream, new TypeToken<List<innerJSON>>(){}.getType());
Now the List will contain as many innerJSON objects as appear in your JSON.

Categories

Resources