I have a nested hashmaps in the below format in my code. When the code is executed, this class also gets executed.
public class NestedHashMap
{
HashMap<String, HashMap<String, HashMap<String, String>>> map1 = new HashMap<String, HashMap<String, HashMap<String, String>>>();
public void hashMapData()
{
HashMap<String, HashMap<String, String>> map2= new HashMap<String, HashMap<String, String>>();
HashMap<String, String> map3 = new HashMap<String, String>();
// map3 contains key as 'Student Exam Code' and value as 'Student Name'.
// map3.put("1352", "ABCDE");
// map3.put("4581", "JDWEF");
// map3.put("1587", "OWELW");
// map2 contains key as 'Exam Centre Code' and value as map3.
// map2.put("CENTRE092", map3);
// map1 contains key as 'Exam Paper Code' and value as map2.
// map1.put("ENG02", map2);
// The data in each hashmap is stored through for loop.
}
public void getData()
{
String strValue = map1.get("ENG02").get("CENTRE092").get("1352");
system.out.println(strValue);
}
}
I am getting the below error when the method 'getData()' gets executed.
java.lang.NullPointerException: Cannot invoke "java.util.HashMap.get(Object)" because the return value of "java.util.HashMap.get(Object)" is null
at scripts.NestedHashMap.getData(NestedHashMap.java:159)
Could someone please help to sort this issue out?
Related
I am trying to map an object to a dictionary in a way that each property will be a dictionary item.
Object with id and name -> dictionary with two items containing property name and value.
I know it is a simple thing, but I was not able to find a solution for it. Maybe it is something I am not understanding...
I receive the following error:
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
=======================================================================================================================================================================================================================================================================
Book -> Dictionary`2 (Destination member list)
Book -> System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] (Destination member list)
Unmapped properties:
Keys
Values
Item
In the following code you can see my implementation:
using AutoMapper;
var book = new Book()
{
Id = 1,
Name = "A"
};
IMapper mapper = new Mapper(new MapperConfiguration(
config => config.CreateMap<Book, Dictionary<string, string>>()
.ConstructUsing((source, dest) => new Dictionary<string, string>()
{
{ "id", source.Id.ToString() },
{"name", source.Name}
})));
mapper.ConfigurationProvider.AssertConfigurationIsValid();
var bookData = new Dictionary<string, string>();
mapper.Map(book, bookData);
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
}
As #Lucian mentioned in a comment, Automapper has built-in methods to convert object from/to dynamic, Dictionary<string, object>.
However, I think that there is an issue if you implement a converter to Dictionary<string, string>.
Hence, it is better to build a custom implementation for the conversion as below:
using System.Reflection;
using Newtonsoft.Json;
public static class DictionaryExtensions
{
public static Dictionary<string, string> ToDictionary<T>(this T src) where T : new()
{
Dictionary<string, string> result = new ();
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo prop in properties)
{
result.Add(prop.Name, prop.PropertyType == typeof(string)
? prop.GetValue(src)?.ToString()
: JsonConvert.SerializeObject(prop.GetValue(src)));
}
return result;
}
}
For caller:
var bookData = book.ToDictionary();
Demo # .NET Fiddle
I am using cucumber 7 and I have the following Then statement in my step definition file:
#Then("^with the following Properties:$")
public void with_the_following_Properties(Map<Gender, String> properties) {
}
This gives me the following exception:
io.cucumber.core.exception.CucumberException: Could not convert arguments for step [^with the following properties:$] defined at 'com.test.glue.TestStepDefs.with_the_following_Properties(java.util.Map<com.test.Gender, java.lang.String>)'.
It appears you did not register a data table type.
at io.cucumber.core.runner.PickleStepDefinitionMatch.registerDataTableTypeInConfiguration(PickleStepDefinitionMatch.java:96)
It seems only Map<String, String> is allowed.
Any suggestion(s).
Cucumber doesn't know how to turn strings into enums. So as the exception message explains you have to register a data table type:
public class StepDefinitions {
#DataTableType
public Gender authorEntryTransformer(String entry) {
return Gender.valueOf(entry);
}
}
I found a simple solution as below :
#Then("^with the following Properties:$")
public void with_the_following_Properties(Map<String, String> properties) {
Map<Gender, String> map = new HashMap<>();
properties.forEach((k, v) -> map.put(Gender.valueOf(k), v));
}
Looking for solution how to match objects from list with data from map with condition if object field starts with map values and save to another map with Groovy
i have map with some data
Map<String, String> dataMap = new HashMap()
dataMap.put("d1", "DATA1")
dataMap.put("d2", "DATA2")
dataMap.put("d3", "DATA3")
and list of DataElement objects
List<DataElement> elements = new ArrayList()
elements.add(new DataElement("TEXT1"))
elements.add(new DataElement("TEXT2"))
elements.add(new DataElement("DATA1_text1"))
elements.add(new DataElement("DATA2_text2"))
class DataElement {
public field;
public DataElement(String text){
this.field = text
}
public getField(){
return this.field
}
And i'am trying to get new Map where keys are values from first map and values are objects(field) from List with condition if object field starts with map value: Result should be:
[d1=DATA1_text1, d2=DATA2_text2]
My code is working but may be there is more elegant variant with using collectEntries:
list = new HashMap()
mapping = dataMap.each { key, v ->
elements.each { el ->
if (el.getField().startsWith(v)) {
list.put(key, el)
}
}
}
dataMap.collectEntries{k,v->
[k,elements.find{e-> e.getField().startsWith(v)} ]
}.findAll{k,v-> v} //to keep only non empty values
I need generic way to filter IQueryable data and filters are populated as dictionary. I have already created method like this.
public static IEnumerable<T> CustomApplyFilter<T>(this IQueryable<T> source, Dictionary<string, string> filterBy)
{
foreach (var key in filterBy.Keys)
{
source.Where(m => m.GetType().GetProperty(key).GetValue(m, null).Equals(filterBy[key]));
}
return source.ToList();
}
But its always returning same result.
please find the caller
Dictionary<string, string> dtFilter = new Dictionary<string, string>();
dtFilter.Add("Id", "2");
var res = context.Set<MyEntity>().CustomApplyFilter<MyEntity>(dtFilter);
The Where extension method does not change the content of the IQueryable it is applied to. The return value of the method should be used:
public static IEnumerable<T> CustomApplyFilter<T>(this IQueryable<T> source, Dictionary<string, string> filterBy)
{
foreach (var key in filterBy.Keys)
{
source = source.Where(m => m.GetType().GetProperty(key).GetValue(m, null).Equals(filterBy[key]));
}
return source.ToList();
}
UPDATE:
I should have noticed it, my answer so far was applicable to LINQ to Objects only. When using LINQ to Entities, however, there are certain restrictions; only expression that can be converted to an SQL query can be used. Getting properties through reflection is not such an expression obviously.
When this is the case, one possible solution would be to build the ExpressionTree manually.
public static IEnumerable<T> CustomApplyFilter<T>(this IQueryable<T> source, Dictionary<string, string> filterBy)
{
foreach (var key in filterBy.Keys)
{
var paramExpr = Expression.Parameter(typeof(T), key);
var keyPropExpr = Expression.Property(paramExpr, key);
var eqExpr = Expression.Equal(keyPropExpr, Expression.Constant(filterBy[key]));
var condExpr = Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr);
source = source.Where(condExpr);
}
return source.ToList();
}
UPDATE2:
With the comment #Venkatesh Kumar given below, it is apparent that when the underlying type of the field provided is not of type string, this solution fails (with the error message : The binary operator Equal is not defined for the types 'System.Int64' and 'System.String').
One possible way to tackle this problem would be to have a dictionary of types and delegates to use for each such property.
Since this is a static method (an extension method which has to be static), declaring a static Dictionary in class scope would be reasonable:
Let's assume the name of the class in which CustomApplyFilter is declared is SOFExtensions:
internal static class SOFExtensions
{
private static Dictionary<Type, Func<string, object>> lookup = new Dictionary<Type, Func<string, object>>();
static SOFExtensions()
{
lookup.Add(typeof(string), x => { return x; });
lookup.Add(typeof(long), x => { return long.Parse(x); });
lookup.Add(typeof(int), x => { return int.Parse(x); });
lookup.Add(typeof(double), x => { return double.Parse(x); });
}
public static IEnumerable<T> CustomApplyFilter<T>(this IQueryable<T> source, Dictionary<string, string> filterBy)
{
foreach (var key in filterBy.Keys)
{
var paramExpr = Expression.Parameter(typeof(T), key);
var keyPropExpr = Expression.Property(paramExpr, key);
if (!lookup.ContainsKey(keyPropExpr.Type))
throw new Exception("Unknown type : " + keyPropExpr.Type.ToString());
var typeDelegate = lookup[keyPropExpr.Type];
var constantExp = typeDelegate(filterBy[key]);
var eqExpr = Expression.Equal(keyPropExpr, Expression.Constant(constantExp));
var condExpr = Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr);
source = source.Where(condExpr);
}
return source.ToList();
}
}
Other types and proper delegates for them should be added to the lookup Dictionary as required.
I want to sort Set of type Map, I have already sorted Map recursively, but when it comes to sort Set of Map and I am not able to sort it. I am not able to do so.
I have tried Override Comparator in TreeSet, but that didn't work.
I am getting below error for TreeSet<Object> sortedSet = new TreeSet(value); line :
TreeSet Cannot sort Set
it gives error message -
java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1290)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
at java.util.TreeSet.addAll(TreeSet.java:312)
at java.util.TreeSet.<init>(TreeSet.java:160)
value is Set( Map (String, Object) ), I want to sort and create a JSON object of it.
public String getSortCode(Object value) {
Set<Object> sortedSet = sortSet((Set<Object>) value);
}
private Set<Object> sortSet(Set<Object> value) {
TreeSet<Object> sortedSet = new TreeSet(value);
sortedSet.forEach(entry -> {
if (entry instanceof Map) {
Map<String, Object> sortedSubMap = sortMap((Map) entry);
sortedSet.add((Object) sortedSubMap);
} else if (entry instanceof Set) {
Set<Object> sortedSubSet = sortSet((Set<Object>) entry);
sortedSet.add((Object) sortedSubSet);
}
});
return (Set<Object>) sortedSet;
}
Thanks in Advance !!
Sushobhit