Convert object to Map<String, String> in java - java

Please suggest how to convert an Object to Map<String, String> in java.
Tried org.apache.commons.beanutils.BeanMap(object).
This is returning Map<String, Object only

How about PropertyUtils.describe(object) though it works only for Java Beans (meaning Java Objects that implement getters)

I am assuming that you want to convert "Object[][] obj" to Map. In that case here is my solution:
public static Map<String, String> convert2DArrayObjectToMap(Object[][] object)
{
Map<String, String> map = new TreeMap<>();
if (object != null)
{
for (int i = 0; i < object.length; i++)
{
if (object[i] != null)
{
for (int j = 0; j < object[i].length; j++)
{
map.putAll((TreeMap<String, String>) object[i][j]);
}
}
}
}
return map;
}

In Java, you can use the Jackson library to convert a Java object into a Map easily.
1 - Get Jackson (pom.xml)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
2 - Convert Object to Map:
import java.util.List;
public class Student {
private String name;
private int age;
private List<String> skills;
// getters setters
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.Map;
public class ObjectToMapExample {
public static void main(String[] args) {
ObjectMapper oMapper = new ObjectMapper();
Student obj = new Student();
obj.setName("Test");
obj.setAge(34);
obj.setSkills(Arrays.asList("java","node"));
// object -> Map
Map<String, Object> map = oMapper.convertValue(obj, Map.class);
System.out.println(map);
}
}
Output:
{name=Test, age=34, skills=[java, node]}

Is there any reason for you not making it manually? It's not that much of a hassle, and you can implement it easily, something like this.
HashMap<String, String> map = new HashMap<>();
//obj represents any object you wanna put inside the map
String key = "your key";
map.put(key, obj.toString());
if the object you want to turn into a map is an iterable object such as a list you can try something like this.
ArrayList<Object> list = new ArrayList<>();
HashMap<String, String> map = new HashMap<>();
Integer i = 0;
for (Object s:list) {
map.put(String.valueOf(i), s.toString());
i++;
}

Iterate over the Map<String, Object> and use newMap.put(key, value.toString()); to fill a new Map<String, String>

Related

Extract and copy values from JSONObject to HashMap

I am having a JSON which contains upto 1000 Keys. I need some specific keys out of it.
Rather than traversing through the JSON and finding key and put its value in required parameter.
I thought of doing it in other way.
I am creating a HashMap of the keys I need.
Now i want to pass a JSONObject through it, where if we find the keys in JSONObject, it will automatically update the HashMap with the required keys.
Is there some function given by Spring where we can do it easily or do I Have to loop through it.
For Example:
JSONObject:-
{
"a":"a",
"b":"b",
"c":"c",
"d":"d",
"e":"e",
}
HashMap that I created :-
Map<String, Object> keys = new HashMap<>();
keys .put("a", "");
keys .put("b", "");
I want a function where i would pass two params
function HashMap mapJsonToHashMap(HashMap, JSONObject) {
}
Returned HashMap would be :-
{
"a":"a",
"b":"b"
}
IMO 1000 keys are not a big deal, so I would go for a simple solution of deserialize it to an object, then just filter/map using streams. Something like:
ObjectMapper objectMapper = new ObjectMapper();
Set<String> keys = new HashSet<>();
keys.add("key-1");
keys.add("key-3");
List<Parameter> list =
objectMapper.readValue("[{ \"key\":\"key-1\", \"value\":\"aaa\" }, { \"key\":\"key-2\", \"value\":\"bbb\" }, { \"key\":\"key-3\", \"value\":\"ccc\" }]", new TypeReference<List<Parameter>>(){});
List<Parameter> filteredList = list.stream()
.filter(l -> keys.contains(l.getKey()))
.collect(Collectors.toList());
// in case you really want to put results in a Map
Map<String, String> KeyValueMap = filteredList.stream()
.collect(Collectors.toMap(Parameter::getKey, Parameter::getValue));
public class Parameter
{
private String key;
private String value;
public String getKey()
{
return key;
}
public void setKey(String key)
{
this.key = key;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
}
You can try something like this,
Convert JSON to HashMap
Then remove unwanted entries from the converted map
public HashMap mapJsonToHashMap(HashMap keys, JSONObject json) {
// Convert JSON to HashMap
ObjectMapper mapper = new ObjectMapper();
Map<String, String> jsonMap = mapper.readValue(json, Map.class);
// Iterate jsonMap and remove invalid keys
for(Iterator<Map.Entry<String, String>> it = jsonMap .entrySet().iterator();
it.hasNext(); ) {
Map.Entry<String, String> entry = it.next();
if(!keys.containsKey(entry.getKey())) {
it.remove();
}
}
return jsonMap;
}

How to check String equality while iterating over two lists?

I have two java classes:
public class MyClass1 {
private String userId;
private String userName;
private List<CustomList1> customList1;
// getters and setters
// inner CustomList1 class
}
public class MyClass2 {
private String userId;
private List<CustomList2> customList2;
// getters and setters
// inner CustomList2 class
}
Now, I have have lists of these classes:
List<MyClass1> classOneList;
List<MyClass2> classTwoList;
In both classOneList and classTwoList lists, object should be sorted with userId ascending. userId in both lists should have same values. What I want to check is that:
Has both lists same size? If not, thow error exception about.
Has every next element from both list the same userId? If not, throw another exception.
Step 1. I have done with simply if statement.
By prototype, step 2. should look like this:
for (el1, el2 : classOneList, classTwoList) {
el1.getUserId().isEqualTo(el2.getUserId());
}
Try the below code for your problem.
public class Testing {
public static void main(String[] args) {
Map<String, List<String>> map1 = new LinkedHashMap<String, List<String>>();
List<String> m1l1 = new LinkedList<String>();
m1l1.add("One");
m1l1.add("Two");
m1l1.add("Three");
m1l1.add("Four");
map1.put("1", m1l1);
List<String> m1l2 = new LinkedList<String>();
m1l2.add("One");
m1l2.add("Two");
m1l2.add("Three");
m1l2.add("Four");
map1.put("2", m1l2);
// Add more element into the map1 by creating more list.
Map<String, List<String>> map2 = new LinkedHashMap<String, List<String>>();
List<String> m2l1 = new LinkedList<String>();
m2l1.add("One");
m2l1.add("Two");
m2l1.add("Three");
m2l1.add("Four");
map2.put("1", m2l1);
// Add more element into the map2 by creating more list.
for (Entry<String, List<String>> entry : map1.entrySet()) {
if (map2.containsKey(entry.getKey())) {
if (entry.getValue().size() == map2.get(entry.getKey()).size()) {
} else {
System.out.println("UserId are same but list are different for userid: " + entry.getKey());
}
}
else {
System.out.println("Userid '"+entry.getKey()+"' exists in map1 but is not found in map2");
}
}
}
}
Hope this may help you.
if(classOneList.size() != classTwoList.size()){
throw new ErrorException();
}else{
classOneList = classOneList.stream().sorted(Comparator.comparing(MyClass1::getUserId)).collect(Collectors.toList());
classTwoList = classTwoList.stream().sorted(Comparator.comparing(MyClass2::getUserId)).collect(Collectors.toList());
for (int i = 0; i < classOneList.size(); i++){
if(!classOneList.get(i).getUserId().equals(classTwoList.get(i).getUserId())){
throw new AnotherErrorException();
}
}
}

Filter pojo properties by some pattern

I've some server response (a long one) which I've converted to POJO (by using moshi library).
Eventually I have list of "Items" , each "Item" looks like follow :
public class Item
{
private String aa;
private String b;
private String abc;
private String ad;
private String dd;
private String qw;
private String arew;
private String tt;
private String asd;
private String aut;
private String id;
...
}
What I actually need, is to pull all properties which start with "a" , and then I need to use their values for further req ...
Any way to achieve it without Reflection ? (usage of streams maybe ?)
Thanks
With guava-functions tranformation you might transform your items with somethng following:
public static void main(String[] args) {
List<Item> items //
Function<Item, Map<String, Object>> transformer = new Function<Item, Map<String, Object>>() {
#Override
public Map<String, Object> apply(Item input) {
Map<String, Object> result = new HashMap<String, Object>();
for (Field f : input.getClass().getDeclaredFields()) {
if(! f.getName().startsWith("a")) {
continue;
}
Object value = null;
try {
value = f.get(input);
} catch (IllegalAccessException e) {
throw new RuntimeException("failed to cast" + e)
}
result.put(f.getName(), value);
}
return result
};
Collection<Map<String, Object> result
= Collections2.transform(items, transformer);
}
Sounds like you may want to perform your filtering on a regular Java map structure.
// Dependencies.
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Map<String, String>> itemAdapter =
moshi.adapter(Types.newParameterizedType(Map.class, String.class, String.class));
String json = "{\"aa\":\"value1\",\"b\":\"value2\",\"abc\":\"value3\"}";
// Usage.
Map<String, String> value = itemAdapter.fromJson(json);
Map<String, String> filtered = value.entrySet().stream().filter(
stringStringEntry -> stringStringEntry.getKey().charAt(0) == 'a')
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
You could wrap up the filtering logic in a custom JsonAdapter, but validation and business logic tends to be nice to leave to the application usage layer.

How to create an enum with map as a field in Java?

I need to create an enum in Java having a field of the type Map. How do I initialize the map field? Is there a way without creating an anonymous object or using Guava (or similar) library?
public enum Day {
Sunday(new HashMap<>()); // TODO initialize the map
private Map<String, String> map;
Day(Map<String, String> paramMap) {
this.map.putAll(paramMap);
}
public getMap() {return map;}
}
This is how it could be done with jdk8 and using functional interface
import java.util.Map;
public interface MapProducer<K,V> {
Map<K,V> getMap();
}
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public enum EnumWithMap {
//empty map
TEST1(HashMap::new),
//default map
TEST2(EnumWithMap::getDefMap),
//enum instance map
TEST3(()->{
Map<String,String> map = new HashMap<>();
map.put("key1","val1");
return map;
})
;
private final Map<String,String> map;
EnumWithMap(MapProducer<String,String> mapProducer) {
this.map = Collections.unmodifiableMap(mapProducer.getMap());
}
private static Map<String,String> getDefMap(){
Map<String,String> map = new HashMap<>();
map.put("keyDef","valDef");
return Collections.unmodifiableMap(map);
}
public Map<String, String> getMap() {
return map;
}
}
$Result of foreach Loop:
for(EnumWithMap en:EnumWithMap.values())System.out.println(en.getMap());
will be:
{}
{keyDef=valDef}
{key1=val1}
Since the key and value of the map are both String, you can make the constructor take a varargs and let it build the map for you:
public enum Day {
SUNDAY("Foo", "Fooz",
"Bar", "Barz",
"Hello", "Hi");
private final Map<String, String> map;
Day(String... keysAndValues) {
if ((keysAndValues.length & 1) != 0)
throw new IllegalArgumentException("keysAndValues has odd size: " + Arrays.toString(keysAndValues));
this.map = new HashMap<>();
for (int i = 0; i < keysAndValues.length; i += 2) {
if (keysAndValues[i] == null || keysAndValues[i + 1] == null)
throw new NullPointerException();
if (this.map.put(keysAndValues[i], keysAndValues[i + 1]) != null)
throw new IllegalArgumentException("keysAndValues has duplicate key named '" + keysAndValues[i] + "': " + Arrays.toString(keysAndValues));
}
}
public Map<String, String> getMap() {
return this.map;
}
}
If you print the map for SUNDAY, e.g. System.out.println(Day.SUNDAY.getMap()), you get:
{Bar=Barz, Hello=Hi, Foo=Fooz}

How to properly lazy initialize Map of Map of Map?

It may be a bad practice, but I haven't been able to figure out any better solution for my problem. So I have this map
// Map<state, Map<transition, Map<property, value>>>
private Map<String, Map<String, Map<String, String>>> properties;
and I want to initialize it so I don't get NullPointerException with this
properties.get("a").get("b").get("c");
I tried this one but I didn't work (obviously)
properties = new HashMap<String, Map<String, Map<String,String>>>();
Other things I tried didn't compile.
Also if you have any ideas how to avoid this nested maps, I would appreciate it.
It seems to me that you need to create your own Key class:
public class Key {
private final String a;
private final String b;
private final String c;
public Key(String a, String b, String c) {
// initialize all fields here
}
// you need to implement equals and hashcode. Eclipse and IntelliJ can do that for you
}
If you implement your own key class, your map will look like this:
Map<Key, String> map = new HashMap<Key, String>();
And when looking for something in the map you can use:
map.get(new Key("a", "b", "c"));
The method above will not throw a NullPointerException.
Please remember that for this solution to work, you need to override equals and hashcode in the Key class. There is help here. If you don't override equals and hashcode, then a new key with the same elements won't match an existing key in the map.
There are other possible solutions but implementing your own key is a pretty clean one in my opinion. If you don't want to use the constructor you can initialize your key with a static method and use something like:
Key.build(a, b, c)
It is up to you.
You need to put maps in your maps in your map. Literally:
properties = new HashMap<String, Map<String, Map<String,String>>>();
properties.put("a", new HashMap<String, Map<String,String>>());
properites.get("a").put("b", new HashMap<String,String>());
If your target is lazy initialization without NPE you have to create your own map:
private static abstract class MyMap<K, V> extends HashMap<K, V> {
#Override
public V get(Object key) {
V val = super.get(key);
if (val == null && key instanceof K) {
put((K)key, val = create());
}
return val;
}
protected abstract V create();
}
public void initialize() {
properties = new MyMap<String, Map<String, Map<String, String>>>() {
#Override
protected Map<String, Map<String, String>> create() {
return new MyMap<String, Map<String, String>>() {
#Override
protected Map<String, String> create() {
return new HashMap<String, String>();
}
};
}
};
}
You could use a utility method:
public static <T> T get(Map<?, ?> properties, Object... keys) {
Map<?, ?> nestedMap = properties;
for (int i = 0; i < keys.length; i++) {
if (i == keys.length - 1) {
#SuppressWarnings("unchecked")
T value = (T) nestedMap.get(keys[i]);
return value;
} else {
nestedMap = (Map<?, ?>) nestedMap.get(keys[i]);
if(nestedMap == null) {
return null;
}
}
}
return null;
}
This can be invoked like this:
String result = get(properties, "a", "b", "c");
Note that care is required when using this as it is not type-safe.
The only way to do it with this structure is to pre-initialise the 1st and 2nd level maps with ALL possible keys. If this is not possible to do you can't achieve what you are asking with plain Maps.
As an alternative you can build a custom data structure that is more forgiving. For example a common trick is for a failed key lookup to return an "empty" structure rather than null, allowing nested access.
You can't initialize this in one go, since you normally don't know what keys you'll have in advance.
Thus you'd have to check whether the submap for a key is null and if so you might add an empty map for that. Preferably you'd only do that when adding entries to the map and upon retrieving entries you return null if one of the submaps in the path doesn't exist. You could wrap that in your own map implementation for ease of use.
As an alternative, apache commons collections' MultiKeyMap might provide what you want.
It's impossible to use properties.get("a").get("b").get("c"); and be sure to avoid null unless you make your own Map. In fact, you can't predict that your map will contains "b" key.
So try to make your own class to handle nested get.
I think a better solution is using an object as the only key to the map of values. The key will be composed of three fields, state, transition and property.
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Key {
private String state;
private String transition;
private String property;
public Key(String state, String transition, String property) {
this.state = state;
this.transition = transition;
this.property = property;
}
#Override
public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
When you check for a value, the map will return null for a key that is not associated with a value
Map<Key, String> values = new HashMap<Key, String>();
assert values.get(new Key("a", "b", "c")) == null;
values.put(new Key("a", "b", "c"), "value");
assert values.get(new Key("a", "b", "c")) != null;
assert values.get(new Key("a", "b", "c")).equals("value");
To efficiently and correctly use an object as a key in a Map you should override the methods equals() and hashCode(). I have built thos methods using the reflective functionalities of the Commons Lang library.
I think, following is the easier way:
public static final Map<Integer, Map<Integer, Map<Integer, Double>>> A_Map = new HashMap<Integer, Map<Integer, Map<Integer, Double>>>()
{
{
put(0, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 60.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 160.0);
put(1, 1 / 13600.0);
}
});
}
});
put(1, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 260.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 560.0);
put(1, 1 / 1300.0);
}
});
}
});
}
};
Using computeIfAbsent/putIfAbsent makes it simple:
private <T> void addValueToMap(String keyA, String keyB, String keyC, String value) {
map.computeIfAbsent(keyA, k -> new HashMap<>())
.computeIfAbsent(keyB, k -> new HashMap<>())
.putIfAbsent(keyC, value);
}

Categories