Problem
Consider a Pojo class with a lot of fields. A HashMap is given. Get element from map and set in object (Update operation). Following should be considered:
- The key name in HashMap and corresponding target field name are not exactly same (see example)
- If a key is not present in map, don't update corresponding field
- If key is present, update corresponding field (including updating with null)
- Do not worry about ClassCastException, map values will be provided with appropriate class type, always.
Example:
Map and Pojo correspondence:
key in HashMap - > field name in Object
- numberOfItems -> quantity
- paidAmount -> price
- adrLine1 -> house
- adrLine2 -> road
- adrLine3 -> area
- adrLine4 -> city
- ...and 100s more
Pojo class:
private static class MyObject{
private Integer quantity;
private Double price;
private String house;
private String road;
private String area;
private String city;
...
//getter-setters
}
A good old plain approach can be:
private void someMethod(Map<String, Object> updateRequest, MyObject obj){
if(updateRequest.containsKey("numberOfItems")){
obj.setQuantity((Integer) updateRequest.get("numberOfItems"));
}
if(updateRequest.containsKey("paidAmount")){
obj.setPrice((Double) updateRequest.get("paidAmount"));
}
if(updateRequest.containsKey("adrLine1")){
obj.setHouse((String) updateRequest.get("adrLine1"));
}
if(updateRequest.containsKey("adrLine2")){
obj.setRoad((String) updateRequest.get("adrLine2"));
}
if(updateRequest.containsKey("adrLine3")){
obj.setArea((String) updateRequest.get("adrLine3"));
}
if(updateRequest.containsKey("adrLine4")){
obj.setCity((String) updateRequest.get("adrLine4"));
}
...
}
But as you can see, this is neither efficient to code, nor comes with a good maintainability.
Something like this would be perfect:
Map<String, Object> updateRequest = //provided
MyObject obj = //provided
List.of(
Pair.of("numberOfItems", "quantity"),
Pair.of("paidAmount", "price"),
Pair.of("adrLine1", "house"),
Pair.of("adrLine2", "road"),
Pair.of("adrLine3", "area"),
Pair.of("adrLine4", "city")
).stream()
.filter(queryPair -> updateRequest.ContainsKey(queryPair.getKey()))
.forEach(queryPair -> obj. set ?? programmatically set field name ?? (updateRequest.get(queryPair.getKey())));
Also feel free to suggest any popular external library that already does this.
CodePudding user response:
Here's a solution that uses lambdas to reify the setters:
Map<String, Object> updateRequest = //provided
MyObject obj = //provided
Map<String, BiConsumer<MyObject, Object>> keyToSetter =
Map.of(
"numberOfItems", (o, v) -> o.setQuantity((Integer) v)
// ...
);
updateRequest.forEach((k, v) -> keyToSetter.get(k).accept(obj, v));
CodePudding user response:
You can convert your existing myObject instance to a map using ObjectMapper and then merge the two maps. Finally you just have to convert the map to MyObject.
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> myObjectMap = mapper.convertValue(obj, HashMap.class);
inputMap.forEach((k,v)-> myObjectMap.merge(k,v, (v1,v2)-> v2));
MyObject resultObject = mapper.convertValue(myObjectMap , MyObject.class);
Notice the remapping function used above. It only sets value from the inputMap. If no value found for a key, it will keep the value in myObjectMap.