Issue with Guava MapDifference is not returning the diffrence but both maps - hashmap

public static Map<String, MapDifference.ValueDifference<String>> mapCompare(HashMap<String, String> hm, HashMap<String,String> hm2){
MapDifference<String, String> diff = Maps.difference(hm, hm2);
Map<String, MapDifference.ValueDifference<String>> entriesDiffering = diff.entriesDiffering();
System.out.println("difrence is -->" +entriesDiffering);
return entriesDiffering;
}
hm1(hashmap1 value)
1:abc 2:xyz 3:eedd 4:[]asdfasd
hm2
1:abc 2:xyz 3:eedd 4:[]asdfas2d
**Notice the hm2 4th key entry has a different value.
Actual OutPut
diffrence is -->{1=(abc 2:xyz 3:eedd 4:[]asdfasd, abc 2:xyz 3:eedd 4:[]asdfas2d)}
Note:- the First key is separated with = in first map, while second map first key is missing altogether) not sure reason. but this is not what i am trying to resolve.
Expected: (Only the difference)
4:[]asdfas2d

It works fine if inputs are proper maps with 4 entries, as shown here (I use Splitter#withKeyValueSeparator to parse string to map:
#Test
public void properlyParsedMaps() {
Map<String, String> map1 = MAP_SPLITTER.split("1:abc 2:xyz 3:eedd 4:[]asdfasd"); // {1=abc, 2=xyz, 3=eedd, 4=[]asdfasd}
Map<String, String> map2 = MAP_SPLITTER.split("1:abc 2:xyz 3:eedd 4:[]asdfas2d"); // {1=abc, 2=xyz, 3=eedd, 4=[]asdfas2d}
mapCompare(map1, map2); // signature slightly changed to accept any `Map`, not just `HashMap`
// difrence is -->{4=([]asdfasd, []asdfas2d)}
}
On the other hand in your example it seems you have maps with one key "1" and value which is the rest of the string (so probably not parsed as you expected):
#Test
public void reverseEngineeredMapsFromOutput() {
Map<String, String> map1 = ImmutableMap.of("1", "abc 2:xyz 3:eedd 4:[]asdfasd"); // {1=abc 2:xyz 3:eedd 4:[]asdfasd}
Map<String, String> map2 = ImmutableMap.of("1", "abc 2:xyz 3:eedd 4:[]asdfas2d"); // {1=abc 2:xyz 3:eedd 4:[]asdfas2d}
mapCompare(map1, map2);
// difrence is -->{1=(abc 2:xyz 3:eedd 4:[]asdfasd, abc 2:xyz 3:eedd 4:[]asdfas2d)}
}
Please make sure you input arguments contain what you expect.

Related

How to map a Map of enum and String in Cucumber 7

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));
}

Accessing keys and values from nested hashmaps in Java

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?

How to fix irregular behavior of string value given by setup method of mapper in mapreduce?

I'm very new to MapReduce and was learning about the implementation of the setup method. The new string value given by configuration is printing correctly but when I tried to further process it, the initial value of the string comes in action. I know the string is immutable, but it should provide the value currently pointing to, to other methods.
public class EMapper extends Mapper<LongWritable, Text, Text, Text> {
String wordstring = "abcd"; //initialized wordstring with "abcd"
public void setup(Context context) {
Configuration config = new Configuration(context.getConfiguration());
wordstring = config.get("mapper.word"); // As string is immutable,
// wordstring should now point to
// value given by mapper.word
//Here mapper.word="ankit" by
//using -D in hadoop command
}
String def = wordstring;
String jkl = String.valueOf(wordstring); //tried to copy current value
//but
//string jkl prints the initial
/value.
public void map(LongWritable key, Text value, Context context)
throws InterruptedException, IOException {
context.write(new Text("wordstring=" + wordstring + " " + "def=" +
def),
new Text("jkl=" + jkl));
}
}
public class EDriver extends Configured implements Tool {
private static Logger logger = LoggerFactory.getLogger(EDriver.class);
public static void main(String[] args) throws Exception {
logger.info("Driver started");
int res = ToolRunner.run(new Configuration(), new EDriver(), args);
System.exit(res);
}
public int run(String[] args) throws Exception {
if (args.length != 2) {
System.err.printf("Usage: %s needsarguments",
getClass().getSimpleName());
return -1;
}
Configuration conf = getConf();
Job job = new Job(conf);
job.setJarByClass(EDriver.class);
job.setJobName("E Record Reader");
job.setMapperClass(EMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setReducerClass(EReducer.class);
job.setNumReduceTasks(0);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.setInputFormatClass(ExcelInputFormat.class);
return job.waitForCompletion(true) ? 0 : 1;
}
}
I expected output to be
wordstring=ankit def=ankit jkl=ankit
Actual output is
wordstring=ankit def=abcd jkl=abcd
This has nothing to do with the mutability of Strings, and everything to do with code execution order.
Your setup method will only be called after any class-level commands are executed. The order you write the code doesn't change anything. If you were to re-write the top section of your code in the order that it actually executes, you'd have:
public class EMapper extends Mapper<LongWritable, Text, Text, Text> {
String wordstring = "abcd";
String jkl = String.valueOf(wordstring);
public void setup(Context context) {
Configuration config = new Configuration(context.getConfiguration());
wordstring = config.get("mapper.word"); //By the time this is called, jkl has already been assigned to "abcd"
}
So it's not surprising that jkl is still abcd. You should set jkl within the setup method, like so:
public class EMapper extends Mapper<LongWritable, Text, Text, Text> {
String wordstring;
String jkl;
public void setup(Context context) {
Configuration config = new Configuration(context.getConfiguration());
wordstring = config.get("mapper.word");
jkl = wordstring;
//Here, jkl and wordstring are both different variables pointing to "ankit"
}
//Here, jkl and wordstring are null, as setup(Context context) has not yet run
public void map(LongWritable key, Text value, Context context)
throws InterruptedException, IOException {
//Here, jkl and wordstring are both different variables pointing to "ankit"
context.write(new Text("wordstring=" + wordstring),
new Text("jkl=" + jkl));
}
Of course you don't actually need jkl, you can just directly use wordstring.
The problem has been solved. Actually, I was running Hadoop in the distributed mode where SETUP, MAPPER, REDUCER, and CLEANUP run on different JVMs. So, data cannot be transported from SETUP to MAPPER directly. The first wordstring object was initialized to "abcd" in mapper. I tried to change the wordstring in SETUP(another object of wordstring was created) which was actually taking place in another JVM.
So, when I tried to copy the "wordstring" in jkl at
String jkl = String.valueOf(wordstring);
the first value of wordstring(the one created by mapper &initialized to "abcd") was being copied to jkl.
If I run Hadoop in standalone mode, it will use a single JVM and the value given to wordstring by SETUP would have been copied to jkl.
Thus, jkl got the copy of wordstring initialized to "abcd" and not the one given by SETUP.
I used
HashMap map=new HashMap();
to transport data between SETUP to MAPPER, and then jkl got a copy of value given by wordstring of SETUP.

how to get value generated in mock method

I have a service method in FooService
public void doSomething(){
ArrayList<Foo> fooList = ...;
barService.batchAddFoos(fooList);
List<String> codeList = new ArrayList<>();
for (Foo foo : fooList) {
codeList.add(foo.getCode());
}
String key = "foo_codes";
redisService.sadd(key,codeList.toArray(new String[]{}));
// other code also need use code
}
BarService.batchAddFoos
for (Foo foo : foos) {
foo.setCode(UUID.randomUUID().toString()); // dynamically generate the code value
}
Then I have a unit test to test FooService logic
#Test
public void doSomething() throws Exception {
fooService.doSomething();
ArgumentCaptor<List<Foo>> fooListCaptor = ArgumentCaptor.forClass(List.class);
verify(barService).batchAddFoos(fooListCaptor.capture());
List<Foo> fooList = fooListCaptor.getValue();
Assert.assertNotNull(fooList.get(0).getCode()); // check code value is generated successfully
List<String> codeList = new ArrayList<>();
for (Foo foo : fooList) {
codeList.add(foo.getCode());
}
verify(redisService).sadd("foo_codes",codeList.toArray(new String[]{}));
}
but it is failed, because the code value is null, actually it does not execute any code in BarService.batchAddFoos.I even tried to explicitly populate code value,
fooList.get(0).setCode("aaa");
fooList.get(1).setCode("bbb");
but it is still failed.
Argument(s) are different! Wanted:
redisService.sadd("foo_codes", "aaa", "bbb");
Actual invocation has different arguments:
redisService.sadd("foo_codes", null, null);
Any idea to solve this problem?
Since the fooList is a local variable of the FooService.doSomething, you cannot populate it from the test. Your test will not fail, if assertion will be as following:
Mockito.verify(barService).batchAddFoos(fooListCaptor.capture());
List<Foo> fooList = fooListCaptor.getValue();
//Assert.assertNotNull(fooList.get(0).getCode());
Assert.assertFalse(fooList.isEmpty());
...
If you will initialize the code in the Foo constructor with Strings.EMPTY or any other not null value, your original assertion will work.
As such scenario, could populate some properties of some object parameters as you like, e.g.
doAnswer(new Answer() {
#Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
List<Foo> fooList = invocationOnMock.getArgumentAt(0, List.class);
fooList.get(0).setCode("aaa"); // explicitly specify the first foo object have code of "aaa"
fooList.get(1).setCode("bbb"); // explicitly specify the second foo object have code of "bbb"
return null;
}
}).when(barService).batchAddFoos(anyList());

When to use C# out keyword on parameter

I've seen some developers use the out keyword on parameter lists of void functions. I'm quite unclear on what the pros and cons are of code below:
List<string> listOfResult;
public void public void (out listOfResult)
{
//bla bla
}
versus
public List<string> c(out listOfResult)
{
List<string> list= new List<string>();
//bla bla
return list;
}
Are these two code snippets perfectly valid or is there any catch around the out keyword?
out keyword is handy when you need to return more than one value from function. Nice example is TryXXX methods, which return status of operation instead of throwing exceptions:
public bool TryParse(string str, out int value);
But I don't see any reason to use single out parameter with void methods... Simply return that value from your method. It will be much easier to use. Compare:
List<string> list;
GetList(out list); // confusing method name
With
List<string> list = GetList(); // nice name, one line of code
If getting of list could throw exceptions, then you can create method like this:
List<string> list;
if (TryGetList(out list)) // better than exception handling
{
// list was filled successfully
}
out parameters are quite handy when you need to return more than one value from a function.
e.g.
Return is a list of results, but you can use an out parameter to return an error message in the case when the list being returned is null.
It's a nice syntax to return multiple parameters. I personally think it's almost always better to model the return of the method as a "new object/class".
That would be:
class CResult
{
List<string> firstResult;
List<string> secondResult;
}
public CResult c()
{
// do something
return new CResult() {firstResult = ..., secondResult = ... };
}
You can see more things related to this approach here.
//out key word is used in function instead of return. we can use multiple parameters by using out key word
public void outKeyword(out string Firstname, out string SecondName)
{
Firstname = "Muhammad";
SecondName = "Ismail";
}
//on button click Event
protected void btnOutKeyword_Click(object sender, EventArgs e)
{
string first, second;
outKeyword(out first, out second);
lblOutKeyword.Text = first + " " + second;
}

Resources