I'm making a code to send data to the payment gateway. I am a beginner in using java. I'm having a bit of trouble working with objects in an array in the item_details parameter. I've made the code as below.
public KeyValuePair<String, String> requestSnapToken(String orderNo,
BigDecimal grossAmount, int paymentMethodId,
String firstName,
String email,
List<FormCartLine> itemDetails
) {
return FAILSAFE_EXECUTOR.get(() -> {
String midtransOrderId = orderNo;
Builder<String, Object> custDetailBuilder = new ImmutableMap.Builder<String, Object>()
.put("first_name", firstName)
.put("last_name", "");
Builder<String, Object> itemDetailsBuilder = new ImmutableMap.Builder<String, Object>();
for (int i = 0; i < itemDetails.size(); i++) {
FormCartLine line = itemDetails.get(i);
int row = i + 1;
itemDetailsBuilder.put($("id%s", row), line.getProductId())
.put($("price%s", row), line.getUnitPricePreTax())
.put($("quantity%s", row), line.getQty())
.put($("name%s", row), line.getName())
.put($("brand%s", row), line.getBrandName())
.put($("category%s", row), line.getCategoryName());
}
Builder<String, Object> payloadBuilder = new ImmutableMap.Builder<String, Object>()
.put("transaction_details", new ImmutableMap.Builder<String, Object>()
.put("order_id", midtransOrderId)
.put("gross_amount", String.valueOf(grossAmount.longValue()))
.build())
.put("item_details", itemDetailsBuilder.build())
});
}
I tried to debug from the code that I made, the payload looks like this. This is not what I wanted..
"transaction_details" : {
"order_id" : "S415",
"gross_amount" : "194547"
},
"item_details" : {
"id1" : "001",
"price1" : 200,
"quantity1" : 1,
"name1" : "Dummy 1",
"brand1" : "Dummy",
"category1" : "Dummies",
"id2" : "002",
"price2" : 300,
"quantity2" : 1,
"name2" : "Dummy 2",
"brand2" : "Dummy",
"category2" : "Dummies"
},
what i want is like below. How do I implement it in java?
"transaction_details" : {
"order_id" : "S415",
"gross_amount" : "194547"
},
"item_details" : [{
"id" : "001",
"price" : 200,
"quantity" : 1,
"name" : "Dummy 1",
"brand" : "Dummy",
"category" : "Dummies"
},
{
"id" : "002",
"price" : 300,
"quantity" : 1,
"name" : "Dummy 2",
"brand" : "Dummy",
"category" : "Dummies"
}
]
Build separate maps for each of your objects and put those maps into a list. Immutability is probably not required, so I'll simplify by using an ArrayList:
final List<Map<String, Object>> itemDetailsList = new ArrayList<>(itemDetails.size());
for (final FormCartLine line : itemDetails) {
itemDetailsList.add(Map.ofEntries(
Map.entry("id", line.getProductId()),
Map.entry("price", line.getUnitPricePreTax()),
// etc.
));
}
// ...
Builder<String, Object> payloadBuilder = new ImmutableMap.Builder<String, Object>()
// .put(...)
.put("item_details", itemDetailsList)
Note that the map returned by Map.ofEntries cannot hold null values, so if that's a requirement, you need to switch to a HashMap<String, Object> or another map type with support for null values.
Of course, you can use an ImmutableMap.Builder too if you prefer or the loop could be converted to use the Java stream API.
Related
I have a map that produces json like this
{
"item": {
"Đã đặt cọc": 0,
"Chờ duyệt": 0,
"Mới tạo": 0,
"Đang đặt hàng": 0,
"Đang VC TQ-VN": 0,
"Đang phát hàng": 0,
"Đã nhận được hàng": 0,
"Đã hủy": 0
},
"name": "Đơn mua hộ"
}
And I want it to be split to this
{
"item": [
{
"name": "Đã đặt cọc",
"count": "0"
},
{
"name": "Chờ duyệt",
"count": "0"
},
...
],
"name": "Đơn kí gửi"
}
I tried this code, but it didn't work
...
HashMap<String, Object> itemSell = new HashMap<>();
// Order Sell
orderSell.put("name", "Đơn mua hộ");
for (Map.Entry<String, Long> pair : reportsStaticSellEcomos.entrySet()) {
itemSell.put("name", pair.getKey());
itemSell.put("count", pair.getValue());
orderSell.put("item", itemSell);
}
summary.add(orderSell);
The code above produces this
{
"item": {
"name": "Đã hủy",
"count": 0
},
"name": "Đơn mua hộ"
}
Yes, it only shows 1 item.
Please help me to get all of them, not only 1
Your item must be a collection of itemSell not an individual element.
Try with this
// Order Sell
orderSell.put("name", "Đơn mua hộ");
List<HashMap<String, Object>> items = new ArrayList<>(reportsStaticSellEcomos.entrySet().size());
for (Map.Entry<String, Long> pair : reportsStaticSellEcomos.entrySet()) {
HashMap<String, Object> itemSell = new HashMap<>();
itemSell.put("name", pair.getKey());
itemSell.put("count", pair.getValue());
items.add(itemSell);
}
orderSell.put("item", items);
summary.add(orderSell);
Also, using a HashMap<String, Object> to represent your Item is not very efficient or easy to understand. Instead you I suggest you create a class Item where you can encapsulate those fields.
public class Item {
private final String name;
private final int count;
// constructor
// equals and hashcode
// getter, setter
}
Your loop repeatedly overwrites the "name" and "count" keys of that itemSell map. You want to use a List here.
...
// Order Sell
orderSell.put("name", "Đơn mua hộ");
List<Map<String, Object>> itemList = new ArrayList<>();
for (Map.Entry<String, Long> pair : reportsStaticSellEcomos.entrySet()) {
Map<String, Object> itemSell = new HashMap<>();
itemSell.put("name", pair.getKey());
itemSell.put("count", pair.getValue());
itemList.add(itemSell);
}
orderSell.put("item", itemList);
summary.add(orderSell);
You might also want to check out Jackson, which can automatically do this sort of thing based on a class structure.
class Order {
String name;
List<Item> items;
}
...
class Item {
String name;
Integer count;
}
...
Order order = ...;
objectMapper.writeValueAsString(order);
I am testing REST api. Below is my JSON response.
[ {
"id" : 1,
"name" : "Chattagram"
}, {
"id" : 2,
"name" : "Rajshahi"
}, {
"id" : 3,
"name" : "Khulna"
}, {
"id" : 4,
"name" : "Barisal"
}, {
"id" : 5,
"name" : "Sylhet"
}, {
"id" : 6,
"name" : "Dhaka"
}, {
"id" : 7,
"name" : "Rangpur"
}, {
"id" : 8,
"name" : "Mymensingh"
} ]
I have converted the list into a List of HashMap. I am able to access the name field but when trying to get the id, below exception is happening. I am not understanding why this exception, cause the key is correct. I have given the debug console image, can any one tell me what is the issue and how i can access the id?
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Source Code :
#Test
public void getEmployees() throws IOException {
final String uri = "http://localhost:8080/public/geocode/divisions";
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
restTemplate.getForObject(uri, String.class);
System.out.println(result);
ObjectMapper mapper = new ObjectMapper();
List<Map<String, String>> list = new ArrayList<>();
list = mapper.readValue(result, List.class);
System.out.println(list.get(0));//--------------out put : {id=1, name=Chattagram}
Map<String, String> m = list.get(0);
System.out.println("id : " + m.get("id")); //------------problem line
System.out.println("Name : " + m.get("name")); //------------working fine
System.out.println(list);
}
After setting a break point in the problem line, debug variables :
Try
System.out.println("id : " + Integer.toString(m.get("id"));
I have 2 lists, the 1st list contains a field that can be duplicated and seconds list contain the same field without duplicate with other fields. What I need is to join the two list to one based on that common field.
List 1 :
[
{
"id" : "1"
"name : "hello",
"item_name": "Name"
},
{
"id" : "1"
"name : "hi"
"item_name": "Name2"
},
{
"id" : "2"
"name : "hello"
"item_name": "Name"
}
]
Second List :
[{
"id" : "1"
"age" : "10",
"place" : "0",
"date" : "0"
},
{
"id" : "2"
"age" : "12",
"place" : "1",
"date" : "0
}]
Expected Result :
[
{
"id" : "1"
"name : "hello",
"item_name": "Name",
**"age" : "10",
"place" : "0",
"date" : "0**
},
{
"id" : "1"
"name : "hi"
"item_name": "Name2"
**"age" : "10",
"place" : "0",
"date" : "0"**
},
{
"id" : "2"
"name : "hello"
"item_name": "Name"
**"age" : "12",
"place" : "1",
"date" : "0"**
}
]
Bold areas are joined from the second list
Please help in this
I have tried :
Map<String, String> listMap = list2
.stream()
.collect(Collectors.toMap(List1Entity::getId,
List1Entity::getId));
list1.forEach(a -> {
a.setPlace(listMap.get(a.getId()));
});
But getting error at .collect(),
no instances or type variable exist so that List2Entity conforms to
List1Entity
Did you mean List2Entity in the first statement?
Map<String, String> listMap = list2
.stream()
.collect(Collectors.toMap(List2Entity::getId,
List2Entity::getPlace));
Your requirements are a bit unclear when it comes to define the joining part between the two lists.
You can start with something like this and adapt mapFunction to your needs.
String list1 = "[{\"id\":\"1\",\"name\":\"hello\",\"item_name\":\"Name\"},{\"id\":\"1\",\"name\":\"hi\",\"item_name\":\"Name2\"},{\"id\":\"2\",\"name\":\"hello\",\"item_name\":\"Name\"}]";
String list2 = "[{\"id\":\"1\",\"age\":\"10\",\"place\":\"0\",\"date\":\"0\"},{\"id\":\"2\",\"age\":\"12\",\"place\":\"1\",\"date\":\"0\"}]";
ObjectMapper mapper = new ObjectMapper();
List<Map<String, Object>> l1 = mapper.readValue(list1, new TypeReference<List<Map<String, Object>>>(){});
List<Map<String, Object>> l2 = mapper.readValue(list2, new TypeReference<List<Map<String, Object>>>(){});
final UnaryOperator<Map<String, Object>> mapFunction = map -> {
final String id = map.get("id").toString();
l2.stream()
.filter(map2 -> map2.get("id").toString().equals(id))
.findAny()
.ifPresent(map::putAll);
return map;
};
List<Map<String, Object>> result = l1
.stream()
.map(mapFunction)
.collect(Collectors.toList());
I want to write a generic code for aggregation using mongoTempalte and Aggregation.group() method. So I have the problem of passing generic fields into the group method with the first() operator
here is my demo native query as follows:
db.subscriberProfile.aggregate([{"$unwind":"$usage_history"},
{ "$group" : { "_id" :"$_id" ,"birthdate" : { "$first":"$birthdate"} , "category" : { "$first":"$category"} , "control_group" : { "$first":"$control_group"} , "sumOfTotalUsage" : { "$sum" :{"$cond": [ { "$gte" :[ "$usage_history.date" , ISODate( "2017-01-13T10:43:55.306Z")] }, "$usage_history.total_usage", 0]}}}},
{ "$match" : { "$and" : [ { "birthdate" : { "$lte" : ISODate( "2017-07-12T10:43:55.306Z")}} , { "birthdate" : { "$gte" : ISODate( "1917-07-12T10:20:35.306Z")}} , { "category" : { "$in" : [ "Prepaid"]}} , { "control_group" : false} , { "sumOfTotalUsage" : { "$gte" : 0}}]}}])
And here is my Sample code in Java.
UnwindOperation unwind = Aggregation.unwind("usage_history");
GroupOperation group = Aggregation.group(fields.toArray(new String[fields.size()])).sum("usage_history.total_usage").as("sumOfTotalUsage");
I just want to know how to add multiple fields in group operation with $first operator.
So, Is there any way to pass list of fields with list of first operator to the group method.
Thanks,
Try this code,I hope this will help you
UnwindOperation unwind = Aggregation.unwind("usage_history");
BasicDBObject object = new BasicDBObject("_id", "$_id");
for (String string : fields) {
object.append(string, new BasicDBObject("$first", "$" + string));
}
object.append("total", new BasicDBObject("$sum", new BasicDBObject("$cond",
new Object[] { new BasicDBObject("$gte", new Object[] { "$usage_history.date", calendarMin.getTime() }),
"$usage_history.total_usage", 0 })));
BasicDBObject groupObject = new BasicDBObject("$group", object);
DBObject groupOperation = (DBObject) groupObject;
MatchOperation matchMain = Aggregation
.match(new Criteria().andOperator(criteriaList.toArray(new Criteria[criteriaList.size()])));
Aggregation aggregation = Aggregation.newAggregation(unwind, new CustomGroupOperation(groupOperation),
matchMain);
Hello all i am trying to match a document using mongodb java driver for eg :
{
"fName" : "abc",
"lName" : "456",
"dob" : "00",
"address" : "xyz"
}
with
"nameIdentity" : [
{
"fName" : "abc",
"lName" : "def",
"dob" : "00",
"address" : "xyz"
},
{
"fName" : "123",
"lName" : "456",
"dob" : "00",
"address" : "789"
}
If i found the document then i don't do anything else add the document. My problem here is if my source document contains fname : abc and lname: 456 this is matching fname in the first set of nameIdentity and lname in the second set of identity. I want this to be a one complete match. I have tried something like this
List<Document> nameIdentities = (List<Document>) matchedDocument.get("nameIdentity");
for (int i=0;i<nameIdentities.size();i++)
{
temp.add(nameIdentities.get(0));
quBasicDBObject=new BasicDBObject("$and",temp);
}
iterable = mongoDatabase.getCollection("entity").find(updatedDocumentTypeOne);
if (iterable.first() == null)
{
updateResult = mongoDatabase.getCollection("entity")
.updateOne(
new Document("_id", new ObjectId(objectId)),
new Document("$push", new Document("nameIdentity", nameList.get(0))));
}
any suggestions where am i going wrong?
UPDATE
You may have to use the aggregation framework.
Maybe something like:
List<Bson> filterList = new ArrayList<>();
filterList.add(new BsonDocument().append("nameIdentity.fName", new BsonString("abc") ));
filterList.add(new BsonDocument().append("nameIdentity.lName", new BsonString("456") ));
FindIterable<org.bson.Document> it = collection.find(Filters.and(filterList));