I have some problem. I get a Response from my RESTful WebServices with JSON Objects in a list. For example:
I get a List of these elements and I want just to get the id from the benutzerId.
[{
"benutzerId": {
"benutzername": "Nenzema",
"geschlecht": "m",
"id": 1,
"nachname": "Marinovic",
"passwort": "test1",
"vorname": "Nenad"
},
"hochzeitId": {
"id": 4
},
"id": 1,
"isbrautbenutzer": true
}, {
"benutzerId": {
"benutzername": "dnikolic",
"geschlecht": "m",
"id": 2,
"nachname": "Nikolic",
"passwort": "test2",
"vorname": "Djordje"
},
"hochzeitId": {
"id": 4
},
"id": 4,
"isbrautbenutzer": false
}]
I already made it, to get just the benutzer, but I dont know how to return a json Object where only the id is in this object, because I dont want to send the whole data to the requester.
[{
"benutzername": "Nenzema",
"geschlecht": "m",
"id": 1,
"nachname": "Marinovic",
"passwort": "test1",
"vorname": "Nenad"
}, {
"benutzername": "dnikolic",
"geschlecht": "m",
"id": 2,
"nachname": "Nikolic",
"passwort": "test2",
"vorname": "Djordje"
}]
So my aim would be to get something like this:
[{
"id": 1
}, {
"id": 2
}]
This is the query for the first list:
#NamedQuery(name = "Hochzeitsplan.findByBenutzerId",
query = "SELECT h FROM Hochzeitsplan h WHERE h.benutzerId.id = :benutzerId"),
These two queries I also tested, but its not working..
#NamedQuery(name = "Hochzeitsplan.getHochzeitsuserByHochzeitsId",
query = "SELECT DISTINCT h.benutzerId FROM Hochzeitsplan h WHERE h.hochzeitId.id = :hochzeitId"),
#NamedQuery(name = "Hochzeitsplan.findBenutzerIdByHochzeitsId",
query = "SELECT h.benutzerId.id FROM Hochzeitsplan h WHERE h.hochzeitId.id = :hochzeitId"),
This is the method I use for getting the Response with the List:
#GET
#Path("/hochzeitIDneu={hochzeitId}")
#Produces({MediaType.APPLICATION_JSON})
public Response getListByHochzeitID(#PathParam("hochzeitId") Integer hochzeitId) {
Query query=em.createNamedQuery("Hochzeitsplan.findByHochzeitId",Hochzeitsplan.class)
.setParameter("hochzeitId", hochzeitId);
List<Hochzeitsplan> a =query.getResultList();
a.sort(new Comparator<Hochzeitsplan>() {
#Override
public int compare(Hochzeitsplan o1, Hochzeitsplan o2)
{
return o1.getId().compareTo(o2.getId());
}
});
if(a.isEmpty()) {
ErrorManager error1 = new ErrorManager();
return Response.status(400).entity(error1.getError(Enums.ErrorResponses.NORESULTS)).build();
} else {
return Response.ok(a.toArray(new Hochzeitsplan[a.size()])).build();
}
}
Use a JsonPath Evaluator like Jayway Jsonpath.
https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path
Your json path can be something like this
$[*]['benutzerId'].id
This would generate output something like
[
1,
2
]
U can try this online https://jsonpath.herokuapp.com
Related
I have a list of objects, and I need to group objects having status equal to my customizedStatusto a single customized one with count = sumOfSameObjectsCount .
We have class MyObject
class MyObject {
Integer id;
String name;
String status;
Long count;
//constructor with attributes
//getters
//setters
}
Suggested implementation :
List<MyObject> resultList = listOfObjects.stream()
.collect(Collectors.groupingBy(MyObject::getStatus))
.entrySet().stream()
.map(e -> e.getValue().stream()
.reduce((partialResult,nextElem) ->
{
LOGGER.info("ahaaaa! inside your reduce block ");
if(partialResult.getStatus().equals(customizedStatus)) {
LOGGER.info("equal to my customizedStatus");
return new MyObject(customizedId, customizedName, customizedStatus, partialResult.getCount()+nextElem.getCount());
} else {
LOGGER.info("not equal to my customizedStatus");
return new MyObject(partialResult.getId(), partialResult.getName(), partialResult.getStatus(), partialResult.getCount());
}
}
)
)
.map(f -> f.get())
.collect(Collectors.toList());
Things work like a charm in case there are multiple objects with status equal to my customizedStatus.
Input :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": ZZ,
"name": "nameZZ",
"status": "customizedStatus",
"count": countZZ
},
{
"id": ZZz,
"name": "nameZZz",
"status": "customizedStatus",
"count": countZZz
}
]
Output :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": customizedId,
"name": "customizedName",
"status": "customizedStatus",
"count": countZZ+countZZz
}
]
In case there is one object with status equal to my customizedStatus, need to be customized it too, unfortunately reduce block is being skipped !
Input :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": ZZ,
"name": "nameZZ",
"status": "customizedStatus",
"count": countZZ
}
]
Output :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": ZZ,
"name": "nameZZ",
"status": "customizedStatus",
"count": countZZ
}
]
Expected output :
[
{
"id": XX,
"name": "nameXX",
"status": "statusXX",
"count": countXX
},
{
"id": YY,
"name": "nameYY",
"status": "statusYY",
"count": countYY
},
{
"id": customizedId,
"name": "customizedName",
"status": "customizedStatus",
"count": countZZ
}
]
It seems like reduce is executed in case there is multiple objects with same status, if there isn't reduce not being executed at all ! Any thoughts to get the expected output using groupBy and reduce ?
Update
The resulting type is not correct. Because you didn't provide the identity within the reduce() it will return an Optional<Object>, but not an object.
For the same reason (because you are using a flavor of reduce() that doesn't expect identity), the accumulator will have no impact on a single element. A quote from the documentation:
Performs a reduction on the elements of this stream, using an
associative accumulation function, and returns an Optional describing
the reduced value, if any. This is equivalent to:
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element;
}
else
result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
The first encountered stream element would become a partial result and there's no more elements, it would be wrapped by the optional as is and returned.
A possible remedy is to introduce the identity:
public static final Integer customizedId = 99;
public static final String customizedName = "customizedName";
public static final String customizedStatus = "customizedStatus";
public static void main(String[] args) {
List<MyObject> listOfObjects =
List.of(new MyObject(1, "nameXX", "statusXX", 1L),
new MyObject(2, "nameYY", "statusYY", 1L),
new MyObject(3, "nameZZz", "customizedStatus", 3L));
List<MyObject> result =
listOfObjects.stream()
.collect(Collectors.groupingBy(MyObject::getStatus))
.entrySet().stream()
.map(e -> e.getValue().stream()
.reduce(getIdentity(e), (partialResult, nextElem) -> accumulate(partialResult, nextElem)) )
.collect(Collectors.toList());
result.forEach(System.out::println);
}
public static MyObject getIdentity(Map.Entry<String, List<MyObject>> entry) {
return entry.getKey().equals(customizedStatus) ?
new MyObject(customizedId, customizedName, customizedStatus, 0L) :
entry.getValue().iterator().next();
}
public static MyObject accumulate(MyObject result, MyObject next) {
return result.getStatus().equals(customizedStatus) ?
new MyObject(customizedId, customizedName, customizedStatus, result.getCount() + next.getCount()) :
new MyObject(result.getId(), result.getName(), result.getStatus(), result.getCount());
}
Output:
MyObject{id=2, name='nameYY', status='statusYY', count=1}
MyObject{id=1, name='nameXX', status='statusXX', count=1}
MyObject{id=99, name='customizedName', status='customizedStatus', count=3}
You can play around with this Online demo
But keep in mind that it's not the brightest idea to try to crap a lot of conditional logic into stream because it becomes more difficult to read.
Solutions provided below were written before the question was updated, and the problem was clarified. Although, they don't target this specific problem, someone might benefit from them and for that reason I'll preserve them.
Reducing the list into a single object
Is there any solution to make it pass by reduce even listOfObjects entries are different by status ?
In case if you want to reduce a list of objects into a single object with a predefined id, name and status, there's no need to create an intermediate map with Collectors.groupingBy().
If you want to utilize reduce() operation for that, you can accumulate count and then create a resulting object based on it:
That's how it might look like (the type of dummy object was changed to MyObject to avoid confusion with java.lang.Object):
final Integer customizedId = // intializing the resulting id
final String customizedName = // intializing the resulting name
final String customizedStatus = // intializing the resulting status
List<MyObject> listOfObjects = // intializing the source list
MyObject resultingObject = listOfObjects.stream()
.map(MyObject::getCount)
.reduce(Long::sum)
.map(count -> new MyObject(customizedId, customizedName, customizedStatus, 0L))
.orElseThrow(); // or .orElse(() -> new MyObject(customizedId, customizedName, customizedStatus, 0L));
Another way of achieving it is to make use of the fact that MyObject is mutable and utilize it as a container inside the collect() operation:
MyObject resultingObject = listOfObjects.stream()
.collect(() -> new MyObject(customizedId, customizedName, customizedStatus, 0L),
(MyObject result, MyObject next) -> result.setCount(result.getCount() + next.getCount()),
(left, right) -> left.setCount(left.getCount() + right.getCount()));
I am really struggling to figure something out in a piece of code I'm working on to pass through a string to multi level JSON. I know that groovy will treat example ="multi.level "$example" as one single property and I have been trying to figure out how to split the string keep the delimiter and then add it to an if statement without any success. I have looked at other solutions but am unable to get them to work in my case... Any help would be appreciated.
JSON:
scriptOutput: [
{
"id": 1,
"data": {
"name": "fyre-discard-vm-1007"
},
"key": "ABCDE123"
},
{
"id": 2,
"data": {
"name": "fyre-discard-vm-1008"
},
"key": "ABCYRE123"
},
{
"id": 3,
"data": {
"name": "fyre-discard-vm-1009"
},
"key": "AZREDE123"
},
{
"id": 4,
"data": {
"name": "fyre-discard-vm-1010"
},
"key": "YTNER857"
},
{
"id": 5,
"data": {
"name": "fyre-discard-vm-1011"
},
"key": "YANT76563A"
},
{
"id": 6,
"data": {
"name": "fyre-discard-vm-1012"
},
"key": "DYAN31685"
},
{
"id": 7,
"data": {
"name": "fyre-discard-vm-1013"
},
"key": "SANF84923"
},
{
"id": 8,
"data": {
"name": "fyre-discard-vm-1014"
},
"key": "SADNS57985"
},
{
"id": 9,
"data": {
"name": "fyre-discard-vm-1015"
},
"key": "DYUIK89OP"
},
{
"id": 10,
"data": {
"name": "fyre-discard-vm-1016"
},
"key": "DHJMNNB6547"
}
]
CODE
#!/usr/local/bin/groovy
import groovy.json.*
def proc7 = "curl https://my-json-server.typicode.com/owainow/privateAPI/machines".execute().text
def slaveList = ["fyre-discard-vm-1007","fyre-discard-vm-1015","fyre-discard-vm-1016"]
def deleteMap=[:]
def jsonName = "data.name"
println "scriptOutput: ${proc7}"
def json = new groovy.json.JsonSlurper().parseText(proc7)
for (slave in slaveList)
{
println(slave);
if (json.find{it.data.name==slave}){ //This works as the properties are passed through as properties
id = json.find{it.data.name==slave}.key
deleteMap = deleteMap+[(slave):(id)]
// I would like to do something like this however I cannot figure out how to split my properties and pass them through in a way that works
/* if (json.find{it."$jsonName"==slave}){ SOMEHOW expand or split jsonName here
id = json.find{it."$jsonName"==slave}.key
deleteMap = deleteMap+[(slave):(id)] */
println "Match"
println (id)
println deleteMap;
}
else{
println"No"
}
}
Cheers guys.
why do you need this? why jsonName should be a string?
Asking this because to get deleteMap from json is quite simple groovy expression:
def deleteMap= json.findAll{ it.data.name in slaveList }.collectEntries{ [it.id, it.data.name] }
however, if you still need it - groovy supports dynamic expression evaluation:
def jsonName = "ROOT.data.name"
def deleteMap= json.findAll{ Eval.me('ROOT', it, jsonName) in slaveList }.collectEntries{ [it.id, Eval.me('ROOT', it, jsonName)] }
I was going to suggest to use the getAt() operator
it[jsonName]
but it turns out that you have a bug in your code, apparently:
id = json.find{it."${jsonName}"==slave}.key
should be
id = json.find{it.data."${jsonName}"==slave}.key
I would still probably use
id = json.find{it.data[jsonName]==slave}.key
Here's complete, corrected snippet:
import groovy.json.*
def proc7 = "curl https://my-json-server.typicode.com/owainow/privateAPI/machines".execute().text
def slaveList = ["fyre-discard-vm-1007","fyre-discard-vm-1015","fyre-discard-vm-1016"]
def deleteMap=[:]
println "scriptOutput: ${proc7}"
def json = new groovy.json.JsonSlurper().parseText(proc7)
for (slave in slaveList)
{
println(slave);
if (json.find{it.data.name==slave}){ //This works as the properties are passed through as properties
id = json.find{it.data.name==slave}.key
deleteMap = deleteMap+[(slave):(id)]
// I would like to do something like this however I cannot figure out how to split my properties and pass them through in a way that works
/* if (json.find{it."$jsonName"==slave}){ SOMEHOW expand or split jsonName here
id = json.find{it."$jsonName"==slave}.key
deleteMap = deleteMap+[(slave):(id)] */
def jsonName="name"
id = json.find{it.data."${jsonName}"==slave}?.key
if (id) {
deleteMap = deleteMap+[(slave):(id)]
println "Match"
println (id)
println deleteMap;
}
}
else{
println"No"
}
}
I am working on computing json format data to use it as Navbar. I have already made the json but there is a column in my database table which specify the order of the menu so I want to return the json on that order only.
My database table is like this:
My Java code is:
String sql="select menu,submenu,link,menu_order from test1";
while(resultSet.next()) {
String menu = resultSet.getString("menu");
String subMenu = resultSet.getString("submenu");
String link = resultSet.getString("link");
map.compute(menu, (key, subMenus) -> {
Map<String, String> mapSubMenu = new LinkedHashMap<>();
mapSubMenu.put("type", subMenu);
mapSubMenu.put("link", link);
subMenus = subMenus != null ? subMenus : new ArrayList<>();
//check for empty or null string otherwise return empty ArrayList
if(!"".equalsIgnoreCase(subMenu) && !"".equalsIgnoreCase(link))
subMenus.add(mapSubMenu);
return subMenus;
});
str = gson.toJson(map);
}
System.out.println(str);
I am getting json from this code like this
{
"India": [
{
"type": "delhi",
"link": "https: //www.google.com"
},
{
"type": "mumbai",
"link": "https: //www.google.com"
}
],
"australia": [
{
"type": "sydney",
"link": "https: //www.google.com"
},
{
"type": "melbourn",
"link": "https: //www.google.com"
}
],
"spain": [
{
"type": "valencia",
"link": "https: //www.google.com"
},
{
"type": "madrid",
"link": "https: //www.google.com"
}
],
"logout": [
]
}
It is displaying data as it is present in my database table, but I have a column as menu_order which defines what should be the order of menu and acc to that there sub menu will come.
How can I achieve that at the Java end or from query end?
You should add an ORDER BY on your query
String sql="select menu,submenu,link,menu_order from test1 ORDER BY menu_order";
I use PostgreSQL and I have these tables, address and company with relation OneToMany on address to company. I want to retrieve a list of addresses which each of them contains a list of companies. I implemented the join between these two tables and I retrieved the data below:
When execute this query:
select ad.id,ad.geolocation, ca.id, ca.name_en, ca.name_el from
address as ad right join company_address as ca on (ad.id = ca.address_id);
I retrieved this table and I want to map it in JSON format as below:
1;"0101000020E6100000C006335CD3043840504BBDB89EC14140"; 6; "Petros";
1;"0101000020E6100000C006335CD3043840504BBDB89EC14140"; 12; "Shop3";
1;"0101000020E6100000C006335CD3043840504BBDB89EC14140"; 13; "Shop3";
7;"0101000020E6100000A03418D984063840D8DD978E94C14140"; 7; "Mike";
7;"0101000020E6100000A03418D984063840D8DD978E94C14140"; 14; "Shop5";
7;"0101000020E6100000A03418D984063840D8DD978E94C14140"; 15; "Shiop8";
9;"0101000020E6100000804127840E163840CC28965B5AC64140"; 10; "Shop2";
9;"0101000020E6100000804127840E163840CC28965B5AC64140"; 11; "Shop3";
Do you know how can convert the results in the format below using an elegant way?
POJO:
private Long id;
private Geolocation geolocation;
private List<ShopObj> shops;
ShopObj Class:
class ShopObj{
private Long id;
private String nameEn;
}
Json Data:
{
"code": "200",
"data": [
{
"id": 1,
"geolocation": "0101000020E6100000C006335CD3043840504BBDB89EC14140",
"shops": [
{
"id": 6,
"nameEn": "Petros"
},
{
"id": 12,
"nameEn": "Shop3"
},
{
"id": 13,
"nameEn": "Shop3"
}
]
},
{
"id": 7,
"geolocation": "0101000020E6100000A03418D984063840D8DD978E94C14140",
"shops": [
{
"id": 7,
"nameEn": "Mike"
},
{
"id": 14,
"nameEn": "Shop5"
},
{
"id": 15,
"nameEn": "Shiop8"
}
]
},
{
"id": 9,
"geolocation": "0101000020E6100000804127840E163840CC28965B5AC64140",
"shops": [
{
"id": 10,
"nameEn": "Shop2"
},
{
"id": 11,
"nameEn": "Shop3"
}
]
}
]
}
Sure.
Create an empty Map<Long, POJO>, containing the POJOs as values, and their ID as keys
Iterate throug your rows.
For each row, get the POJO ID, and get the corresponding POJO from the map. If it's not in the map yet, create the POJO and add it to the map
create a Shop for the current row, and add the shop to the list of shops of the POJOs obtained/created at the previous step
At the end, the values() of the map is the Collection<POJO> that you want to serialize to JSON.
I implemented the code below and worked for my case, but do you know if is there and auto way to map my data?
List<ProductTest> productTests = productRepository.getProductTest();
Map<Long, ProductT> products = new HashMap<Long, ProductT>();
for (ProductTest pt : productTests) {
ProductT productT = products.get(pt.getId());
if (productT == null) {
productT = new ProductT(pt.getId(), pt.getNameEl(), new ArrayList<MediaT>());
products.put(pt.getId(), productT);
}
MediaT mediaT = new MediaT(pt.getMediaId(), pt.getMultimediaPath());
productT.getMediaList().add(mediaT);
}
return products.values();
[
{
"ID": 5,
"Name": "pratik"
},
{
"ID": 6,
"Name": "pratiksha"
},
{
"ID": 7,
"Name": "pratikshaman"
}
]
I want to display only : 6 Pratiksha
Not too clear on what your trying to achieve... is this what your wanting?
//The json string
var jsonString = '[{"ID":5,"Name":"pratik"},{"ID":6,"Name":"pratiksha"},{"ID":7,"Name":"pratikshaman"}]',
//The json array
jsonArray = JSON.parse(jsonString),
//search function to returns entry by id
jsonSearch = function(id){
return jsonArray.filter(function(obj){
return obj.ID === id;
});
};
console.log(jsonSearch(6)); //Array contains your Pratiksha object and any other matches
http://jsfiddle.net/uckpL5bt/