To attribute Map below in a class that i want to save and read from Dyanmodb, using DynamoDBMapper.
Map<String, Map<String, Transition>> twf;
public class Transition {
public String fst;
public Permission pm;
public List<Action> ac;
}
public class Action {
private String mdl;
private String dsc;
private String nm;
// email address or any other data
private Map<String, String> data;
}
i have tried DynamoDBTypeConverted to convert to String, that results in json string that has " escaped as \" and unreadable in dyanmodb. I wanted to store as json
I implemented with understanding that Dyanmodb supports Map, but i still get error :
Exception processing message: not supported; requires #DynamoDBTyped or #DynamoDBTypeConverted
public class TimeSheetWorkFlowConverter implements
DynamoDBTypeConverter<Map<String, Object>, Map<String, Map<String, Transition>>> {
#Override
public Map convert(Map<String, Map<String, Transition>> object) {
// Map obj = mapper.readValue(object, Map.class);
String newJson = null;
Map objectJson = null;
try {
newJson = mapper.writeValueAsString(object);
objectJson = mapper.readValue(newJson, Map.class);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return objectJson;
}
#SuppressWarnings("unchecked")
#Override
public Map<String, Map<String, Transition>> unconvert(Map<String, Object> object) {
Map<String, Map<String, Transition>> wf = new HashMap<>();
if (object != null && !object.isEmpty())
for (Entry<String, Object> entry : object.entrySet()) {
String key = entry.getKey();
Map<String, Transition> value = mapTransition(entry.getValue());
wf.put(key, value);
}
return wf;
}
#RequestMapping("/regressionTest")
public String home(Model model, #ModelAttribute CleanupTitles cleanupTitles) {
applicationToEnvStatus = MappingUtil
.getApplicationToEnvStatusMapping(databaseOperation);
model.addAttribute("parameters", new Parameters());
model.addAttribute("cleanupTitle", cleanupTitles);
cleanupTitles.setTitles(databaseOperation.getTitle());
return "home";
}
MappingUtil class
public class MappingUtil {
private enum Environment {
dev, stage, prod
}
private static Map<String, String> applicationToStatus;
private static Map<String, List<String>> applicationToEnvStatus;
public static Map<String,List<String>> getApplicationToEnvStatusMapping(
DatabaseOperation databaseOperation) {
applicationToStatus = new HashMap<String, String>();
applicationToEnvStatus = new HashMap<String, List<String>>();
for (Environment e : Environment.values()) {
System.out.println(e.toString());
applicationToStatus = databaseOperation
.getApplicationToEnvMapping(e.toString());
for (Map.Entry<String, String> entry : applicationToStatus
.entrySet()) {
List<String> li = new ArrayList<String>();
li.add(e.toString());
li.add(entry.getValue());
applicationToEnvStatus.put(entry.getKey(), li);
}
//System.out.println(e.toString() + " " + applicationToStatus);
}
System.out.println(applicationToEnvStatus);
return applicationToEnvStatus;
}
Database call
public Map<String, String> getApplicationToEnvMapping(String envName) {
String sqlQuery = "select application_name,is_completed from (select application_name,is_completed from rtf_run_status where env='"
+ envName + "' order by date_created desc) where rownum<=3";
Map<String, String> applicationToStatus = new HashMap<String, String>();
jdbcTemplate.query(sqlQuery, new ResultSetExtractor<Map>() {
#Override
public Map extractData(ResultSet rs) throws SQLException,
DataAccessException {
while (rs.next()) {
applicationToStatus.put(rs.getString("application_name"),
rs.getString("is_completed"));
}
return applicationToStatus;
}
});
return applicationToStatus;
}
The controller is making 2 db calls to: a) MappingUtil.getApplicationToEnvStatus() and b) cleanupTitles.setTitles(). This results in view taking a lot of time to load. The result set returned from each query is around 4-5.
What would be the best approach to load view at a faster response time? Should I execute db calls in a new Thread or is there any better way of doing this?
I have class Rowdata
public class FileData {
Map<Long, List<String>> cacheData = new LinkedHashMap<Long, List<String>>();
List<String> header = new ArrayList<String>();
public Map<Long, List<String>> getCacheData() {
return Collections.unmodifiableMap(cacheData);
}
public List<String> getHeaderMapping() throws Exception {
return header;
}
public void putData(long key, List<String> row) {
cacheData.put(key, row);
}
public int size() {
return cacheData.size();
}
public void setHeader(List<String> header) {
this.header = header;
}
}
I would like persist this object. What is the best way to persist? Shall I proceed with RDBMS? then what is the table schema?
Or Shall I proceed with NoSQL? then We already have CouchDB in our project . Please advice on this.
I get an object and a map in the method, and I need to migrate all object field values to a map. Which will be later saved in the DB. Values of the map cannot be null.
This is the code:
public static final EMP_LAST_NAME_ATTR = "firstName";
public static final EMP_FIRST_NAME_ATTR = "lastName";
...ect.
and
public void addAttributes(Map<String, String> attributes, Employee employee) {
if (StringUtils.isNotBlank(employee.getFirstName())) {
attributes.put(EMP_FIRST_NAME_ATTR, employee.getFirstName());
}
if (StringUtils.isNotBlank(employee.getLastName())) {
attributes.put(EMP_LAST_NAME_ATTR, employee.getLastName());
}
if (StringUtils.isNotBlank(employee.getEmail())) {
attributes.put(EMP_EMAIL_ATTR, employee.getEmail());
}
...etc many more ifs
}
Unfortunately it has to be a map, as the DB table is created as key/value, and I can't change the the entities.
Any way of shortening this IF nightmare?
One way would be to refactor the if block into its own method:
private void putIfNotBlank(Map<String, String> attributes, String key, String value) {
if (StringUtils.isNotBlank(value)) {
attributes.put(key, values);
}
}
and your method beomes easier to read:
public void addAttributes(Map<String, String> attributes, Employee employee) {
putIfNotBlank(attributes, EMP_FIRST_NAME_ATTR, employee.getFirstName());
putIfNotBlank(attributes, EMP_LAST_NAME_ATTR, employee.getLastName());
putIfNotBlank(attributes, EMP_EMAIL_ATTR, employee.getEmail());
}
private void addAttribute(Map<String, String> attributes, String key, String value) {
if (StringUtils.isNotBlank(value)) {
attributes.put(key, value);
}
}
public void addAttributes(Map<String, String> attributes, Employee employee) {
addAttribute(attributes, EMP_FIRST_NAME_ATTR, employee.getFirstName());
addAttribute(attributes, EMP_LAST_NAME_ATTR, employee.getLastName());
addAttribute(attributes, EMP_EMAIL_ATTR, employee.getEmail());
}
Make a method to do it for you.
public void addAttributes(Map<String,String> attributes, Employee employee)
{
addAttribute(attributes, EMP_FIRST_NAME_ATTR, employee.getFirstName());
addAttribute(attributes, EMP_LAST_NAME_ATTR, employee.getLastName());
.....
}
private void addAttribute(Map<String,String> attributes, String ATTR_NAME, String value)
{
if(StringUtils.isNotBlank(value)) attributes.put(ATTR_NAME, value);
}
Problem solved.
Do some refactoring by creating a utility method that captures the essence of the check:
public static void putIfNotBlank(Map<String, String> map, String key, String value) {
if (StringUtils.isNotBlank(value))
map.put(key, value);
}
Then call it for each attribute:
putIfNotBlank(attributes, EMP_EMAIL_ATTR, employee.getEmail());
Use Jackson Json ObjectMapper library
ObjectMapper mapper = new ObjectMapper();
Map<String,String> map = mapper.convert(mapper.writeValueAsString(<yourObject),new TypeReference<HashMap<String,String>>(){});
You could define a new Map that had this behaviour built in:
public class NonBlankValueMap extends HashMap<String, String> {
#Override
public String put(String key, String value) {
if (StringUtils.isNotBlank(value))
return super.put(key, value);
return null;
}
}
Then simply:
Map<String, String> attributes = new NonBlankValueMap();
And:
attributes.put(EMP_FIRST_NAME_ATTR, employee.getFirstName());
I have a HashMap in Java, the contents of which (as you all probably know) can be accessed by
HashMap.get("keyname");
If a have a HashMap inside another HashMap i.e. a nested HashMap, how would i access the contents? Can i do this like this, inline:
HashMap.get("keyname").get("nestedkeyname");
Thank you.
You can do it like you assumed. But your HashMap has to be templated:
Map<String, Map<String, String>> map =
new HashMap<String, Map<String, String>>();
Otherwise you have to do a cast to Map after you retrieve the second map from the first.
Map map = new HashMap();
((Map)map.get( "keyname" )).get( "nestedkeyname" );
You can get the nested value by repeating .get(), but with deeply nested maps you have to do a lot of casting into Map. An easier way is to use a generic method for getting a nested value.
Implementation
public static <T> T getNestedValue(Map map, String... keys) {
Object value = map;
for (String key : keys) {
value = ((Map) value).get(key);
}
return (T) value;
}
Usage
// Map contents with string and even a list:
{
"data": {
"vehicles": {
"list": [
{
"registration": {
"owner": {
"id": "3643619"
}
}
}
]
}
}
}
List<Map> list = getNestedValue(mapContents, "data", "vehicles", "list");
Map first = list.get(0);
String id = getNestedValue(first, "registration", "owner", "id");
Yes.
See:
public static void main(String args[]) {
HashMap<String, HashMap<String, Object>> map = new HashMap<String, HashMap<String,Object>>();
map.put("key", new HashMap<String, Object>());
map.get("key").put("key2", "val2");
System.out.println(map.get("key").get("key2"));
}
If you plan on constructing HashMaps with variable depth, use a recursive data structure.
Below is an implementation providing a sample interface:
class NestedMap<K, V> {
private final HashMap<K, NestedMap> child;
private V value;
public NestedMap() {
child = new HashMap<>();
value = null;
}
public boolean hasChild(K k) {
return this.child.containsKey(k);
}
public NestedMap<K, V> getChild(K k) {
return this.child.get(k);
}
public void makeChild(K k) {
this.child.put(k, new NestedMap());
}
public V getValue() {
return value;
}
public void setValue(V v) {
value = v;
}
}
and example usage:
class NestedMapIllustration {
public static void main(String[] args) {
NestedMap<Character, String> m = new NestedMap<>();
m.makeChild('f');
m.getChild('f').makeChild('o');
m.getChild('f').getChild('o').makeChild('o');
m.getChild('f').getChild('o').getChild('o').setValue("bar");
System.out.println(
"nested element at 'f' -> 'o' -> 'o' is " +
m.getChild('f').getChild('o').getChild('o').getValue());
}
}
As others have said you can do this but you should define the map with generics like so:
Map<String, Map<String, String>> map = new HashMap<String, Map<String,String>>();
However, if you just blindly run the following:
map.get("keyname").get("nestedkeyname");
you will get a null pointer exception whenever keyname is not in the map and your program will crash. You really should add the following check:
String valueFromMap = null;
if(map.containsKey("keyname")){
valueFromMap = map.get("keyname").get("nestedkeyname");
}
Yes, if you use the proper generic type signature for the outer hashmap.
HashMap<String, HashMap<String, Foo>> hm = new HashMap<String, HashMap<String, Foobar>>();
// populate the map
hm.get("keyname").get("nestedkeyname");
If you're not using generics, you'd have to do a cast to convert the object retrieved from the outer hash map to a HashMap (or at least a Map) before you could call its get() method. But you should be using generics ;-)
I prefer creating a custom map that extends HashMap. Then just override get() to add extra logic so that if the map doesnt contain your key. It will a create a new instance of the nested map, add it, then return it.
public class KMap<K, V> extends HashMap<K, V> {
public KMap() {
super();
}
#Override
public V get(Object key) {
if (this.containsKey(key)) {
return super.get(key);
} else {
Map<K, V> value = new KMap<K, V>();
super.put((K)key, (V)value);
return (V)value;
}
}
}
Now you can use it like so:
Map<Integer, Map<Integer, Map<String, Object>>> nestedMap = new KMap<Integer, Map<Integer, Map<String, Object>>>();
Map<String, Object> map = (Map<String, Object>) nestedMap.get(1).get(2);
Object obj= new Object();
map.put(someKey, obj);
I came to this StackOverflow page looking for a something ala valueForKeyPath known from objc. I also came by another post - "Key-Value Coding" for Java, but ended up writing my own.
I'm still looking for at better solution than PropertyUtils.getProperty in apache's beanutils library.
Usage
Map<String, Object> json = ...
public String getOptionalFirstName() {
return MyCode.getString(json, "contact", "firstName");
}
Implementation
public static String getString(Object object, String key0, String key1) {
if (key0 == null) {
return null;
}
if (key1 == null) {
return null;
}
if (object instanceof Map == false) {
return null;
}
#SuppressWarnings("unchecked")
Map<Object, Object> map = (Map<Object, Object>)object;
Object object1 = map.get(key0);
if (object1 instanceof Map == false) {
return null;
}
#SuppressWarnings("unchecked")
Map<Object, Object> map1 = (Map<Object, Object>)object1;
Object valueObject = map1.get(key1);
if (valueObject instanceof String == false) {
return null;
}
return (String)valueObject;
}
import java.util.*;
public class MyFirstJava {
public static void main(String[] args)
{
Animal dog = new Animal();
dog.Info("Dog","Breezi","Lab","Chicken liver");
dog.Getname();
Animal dog2= new Animal();
dog2.Info("Dog", "pumpkin", "POM", "Pedigree");
dog2.Getname();
HashMap<String, HashMap<String, Object>> dogs = new HashMap<>();
dogs.put("dog1", new HashMap<>() {{put("Name",dog.name);
put("Food",dog.food);put("Age",3);}});
dogs.put("dog2", new HashMap<>() {{put("Name",dog2.name);
put("Food",dog2.food);put("Age",6);}});
//dogs.get("dog1");
System.out.print(dogs + "\n");
System.out.print(dogs.get("dog1").get("Age"));
}
}
Example Map:
{
"data": {
"userData": {
"location": {
"city": "Banja Luka"
}
}
}
}
Implementation:
public static Object getValueFromMap(final Map<String, Object> map, final String key) {
try {
final String[] tmpKeys = key.split("\\.");
Map<String, Object> currentMap = map;
for (int i = 0; i < tmpKeys.length - 1; i++) {
currentMap = (Map<String, Object>) currentMap.get(tmpKeys[i]);
}
return currentMap.get(tmpKeys[tmpKeys.length - 1]);
} catch (Exception exception) {
return null;
}
}
Usage:
final Map<String, Object> data = new HashMap<>();
final Map<String, Object> userData = new HashMap<>();
final Map<String, Object> location = new HashMap<>();
location.put("city", "Banja Luka");
userData.put("location", location);
data.put("userData", userData);
System.out.println(getValueFromMap(data, "userData.location.city"));
Result:
Banja Luka
Process finished with exit code 0
I hit this discussion while trying to figure out how to get a value from a nested map of unknown depth and it helped me come up with the following solution to my problem. It is overkill for the original question but maybe it will be helpful to someone that finds themselves in a situation where you have less knowledge about the map being searched.
private static Object pullNestedVal(
Map<Object, Object> vmap,
Object ... keys) {
if ((keys.length == 0) || (vmap.size() == 0)) {
return null;
} else if (keys.length == 1) {
return vmap.get(keys[0]);
}
Object stageObj = vmap.get(keys[0]);
if (stageObj instanceof Map) {
Map<Object, Object> smap = (Map<Object, Object>) stageObj;
Object[] skeys = Arrays.copyOfRange(keys, 1, keys.length);
return pullNestedVal(smap, skeys);
} else {
return null;
}
}