I'm trying to create a custom Itemreader using a HashMap, here is an eaxmple i find it of an itemReader using a list instead of HashMap
public class InMemoryStudentReader implements ItemReader<StudentDTO> {
private int nextStudentIndex;
private List<StudentDTO> studentData;
InMemoryStudentReader() {
initialize();
}
private void initialize() {
StudentDTO tony = new StudentDTO();
tony.setEmailAddress("tony.tester#gmail.com");
tony.setName("Tony Tester");
tony.setPurchasedPackage("master");
StudentDTO nick = new StudentDTO();
nick.setEmailAddress("nick.newbie#gmail.com");
nick.setName("Nick Newbie");
nick.setPurchasedPackage("starter");
StudentDTO ian = new StudentDTO();
ian.setEmailAddress("ian.intermediate#gmail.com");
ian.setName("Ian Intermediate");
ian.setPurchasedPackage("intermediate");
studentData = Collections.unmodifiableList(Arrays.asList(tony, nick, ian));
nextStudentIndex = 0;
}
#Override
public StudentDTO read() throws Exception {
StudentDTO nextStudent = null;
if (nextStudentIndex < studentData.size()) {
nextStudent = studentData.get(nextStudentIndex);
nextStudentIndex++;
}
return nextStudent;
}
}
As you can see here we can iterate on a list by it's position (index), so when we call next time the method read() we garantie that we get the next elment.
But in my case the is no notion of index, as HashMap has no concept of position so there is no way to get an object by position.
haw can update this code to work with my case:
public class InMemoryMouvementReader implements ItemReader<MouvementFileRow> {
#Autowired
private MouvementToMap mvts;
#Override
public MouvementFileRow read() throws Exception {
MouvementFileRow nextMouvement = null;
// the Map
// public Map<Long, MouvementFileRow> getMouvmentFileRowMap() {
// return mouvmentFileRowMap;
// }
mvts.getMouvmentFileRowMap()
return nextMouvement;
}
}
do i need to change the hashMap to LinkedHashMap instead or to convert map to List ?
There are no indexes like 0, 1, ... n but you can use the keys in an specific order (e.g. alphabetic sort). Another approach is to get a Iterator object by calling yourHashMap.keySet().iterator() and use that object as class-attribute instead of the nextStudentIndex-attribute. Then use a code snippet like:
if (yourIterator.hasNext()) return yourHashMap.get(youtIterator.next());
else return null;
If you don't want to use any kind of index in your implementation, then read(idx) can be written in the loop, where read() is going to be called idx times.
Related
I am trying to loop through a HashMap, then for each key I want to access the object (Shipment) that is associated to the key and access my array list for further analysis purposes. Each object/key in HashMap has the same array list (metricList). I cannot seem to access it, though I have checked the private/public thing. Can someone point me in the right direction?
I think I need to maybe get the class of my object and then use the method "getList"... I tried with no luck.
This is a sample of the code (removed irrelevant parts) if it helps:
This is my object:
public class Shipment{
//Members of shipment
private final String shipment;
public Date creationDate;
public int creationTiming;
public int processingTiming;
public ArrayList<Integer> metricList;
public void createArrayList() {
// create list
metricList = new ArrayList<Integer>();
// add metric to list
metricList.add(creationTiming);
metricList.add(processingTiming);
}
public ArrayList<Integer> getList() {
return metricList;
}
}
This is the class where I create a hashMap and run through different analysis:
public class AnalysisMain {
public static Map<String, Shipment> shipMap = new HashMap();
public static void main(String[] args) {
try {
... // Different calls to analysis
}
catch {}
}
}
This is where the issue occurs (it does not recognize that I already have a "metricList", asking if I want to create local variable)
public class Metric_Analysis{
public static void analyze() throws Exception{
ResultSet rs;
try {
rs = getSQL("SELECT * FROM TEST_METRICS");
}
catch(Exception e) {
//Pass the error
throw new java.lang.Exception("DB Error: " + e.getMessage());
}
Iterator<Map.Entry<String, Shipment>> iterator = shipMap.entrySet().iterator();
while(iterator.hasNext()){
Iterator<String> metricIterator = metricList.iterator();
//Above is the Array List I want to access and loop through
//I will then perform certain checked against other values on a table...
while (metricIterator.hasNext()) {
//I will perform certain things here
}
}
}
}
You need to get the List out of your Shipment.
You can access the object from the iterator with: iterator.next();
This will also set the pointer to the next Entry in your List/Map.
Change your code:
Iterator<Map.Entry<String, Shipment>> iterator = shipMap.entrySet().iterator();
while(iterator.hasNext()){
// Get the Entry from your Map and get the value from the Entry
Entry<String, Shipment> entry = iterator.next();
List<Integer> metricList = entry.getValue().getList();
Iterator<String> metricIterator = metricList.iterator();
//Above is the Array List I want to access and loop through
//I will then perform certain checked against other values on a table...
while (metricIterator.hasNext()) {
//I will perform certain things here
}
}
I have a test in which I have a set of specific values for which two different methods will execute once for each value in the set. I need to check that the two methods are called in a specific order in relation to each other, but not in relation to the order of the set of values. For example:
String[] values = { "A", "B", "C" };
for (...<loop over values...) {
methodOne(value);
methodTwo(value);
}
It does not matter which order values is in, but I need to verify that methodOne() and methodTwo() are called for each value in the set AND that methodOne() is always called before methodTwo().
I know that I can create a control and expect methodOne() and methodTwo() for each value, then do control.verify(), but this depends on values being in a specific order.
Is there an elegant way to do this?
Thanks
You can do this using andAnswer().
Basically, inside the andAnswer() from methodOne() you set some variable to hold what the passed in value was.
Then in the andAnswer() for methodTwo() you assert that the same argument matches what you saved from your methodOne answer.
Since each call to methodOne will modify this variable it will make sure methodTwo() is always called after methodOne().
Note this solution is not thread safe
First you need something to hold the variable from the methodOne call. This can be a simple class with a single field or even an array of one element. You need this wrapper object because you need to reference it in the IAnswer which requires a final or effectively final field.
private class CurrentValue{
private String methodOneArg;
}
Now your expectations. Here I called the class that you are testing (The System Under Test) sut:
String[] values = new String[]{"A", "B", "C"};
final CurrentValue currentValue = new CurrentValue();
sut.methodOne(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
//save the parameter passed in to our holder object
currentValue.methodOneArg =(String) EasyMock.getCurrentArguments()[0];
return null;
}
}).times(values.length); // do this once for every element in values
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
//check to make sure the parameter matches the
//the most recent call to methodOne()
assertEquals(currentValue.methodOneArg, value);
return null;
}
}).times(values.length); // do this once for every element in values
replay(sut);
... //do your test
verify(sut);
EDIT
you are correct that if you are using EasyMock 2.4 + you can use the new Capture class to get the argument value in a cleaner way for methodOne(). However, you may still need to use the andAnswer() for methodTwo() to make sure the correct values are called in order.
Here is the same code using Capture
Capture<String> captureArg = new Capture<>();
sut.methodOne(and(capture(captureArg), isA(String.class)));
expectLastCall().times(values.length);
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
assertEquals(captureArg.getValue(), value);
return null;
}
}).times(values.length);
replay(sut);
For those interested, I solved this issue using intended EasyMock functionality. The solution was to make a custom IArgumentMatcher to verify against a collection of values and to enforce how many times each value is matched consecutively. The custom matcher, in addition to using strict mocking exactly solves the original problem.
public class SetMatcher implements IArgumentMatcher {
private List<String> valuesToMatch;
private List<String> remainingValues;
private String currentValue = null;
private int timesMatched = 0;
private int setMatches;
public SetMatcher(final List<String> valuesToMatch, final int times) {
this.valuesToMatch = new ArrayList<String>(valuesToMatch);
this.remainingValues = new ArrayList<String>(valuesToMatch);
this.setMatches = times;
}
public String use() {
EasyMock.reportMatcher(this);
return null;
}
public void appendTo(StringBuffer buffer) {
if (this.remainingValues.size() == 0) {
buffer.append("all values in " + this.valuesToMatch + " already matched " + this.setMatches + " time(s)");
} else {
buffer.append("match " + this.valuesToMatch + " " + this.setMatches + " time(s) each");
}
}
public boolean matches(Object other) {
if (this.timesMatched >= this.setMatches) {
this.currentValue = null;
this.timesMatched = 0;
}
if (null == this.currentValue) {
if (this.remainingValues.contains(other)) {
this.currentValue = (String) other;
this.timesMatched = 1;
this.remainingValues.remove(other);
return true;
}
} else if (this.currentValue.equals(other)) {
this.timesMatched++;
return true;
}
return false;
}
}
The class being tested:
public class DataProcessor {
private ServiceOne serviceOne;
private ServiceTwo serviceTwo;
public DataProcessor(ServiceOne serviceOne, ServiceTwo serviceTwo) {
this.serviceOne = serviceOne;
this.serviceTwo = serviceTwo;
}
public void processAll(List<String> allValues) {
List<String> copy = new ArrayList<String>(allValues);
for (String value : copy) {
this.serviceOne.preProcessData(value);
this.serviceTwo.completeTransaction(value);
}
}
}
And the test:
public class DataProcessorTest {
List<String> TEST_VALUES = Arrays.asList("One", "Two", "Three", "Four", "Five");
#Test
public void test() {
IMocksControl control = EasyMock.createStrictControl();
ServiceOne serviceOne = control.createMock(ServiceOne.class);
ServiceTwo serviceTwo = control.createMock(ServiceTwo.class);
SetMatcher matcher = new SetMatcher(TEST_VALUES, 2);
for (int i = 0; i < TEST_VALUES.size(); i++) {
serviceOne.preProcessData(matcher.use());
serviceTwo.completeTransaction(matcher.use());
}
control.replay();
DataProcessor dataProcessor = new DataProcessor(serviceOne, serviceTwo);
dataProcessor.processAll(TEST_VALUES);
control.verify();
}
}
The test will fail for any of the following:
ServiceOne and ServiceTwo are called in the wrong order
ServiceOne and ServiceTwo are not called consecutively with the same value
ServiceOne or ServiceTwo are called with a value that is not in the specified value list
A call is made beyond the number of expected times for a value in the list
I have a Java class with following implementation:
class Some {
private ArrayList<SomeObject> list = new...
public void addToList(Long t) {
SomeObject so = new SomeObject(new Date, t)
list.add(so)
}
private float fun1(ArrayList<SomeObject> x) {
//some operations on list "list",
//res - result of float calculations based on list "x"
return res
}
public float publicFun() {
//some other operations on private list "list"
return fun1(list);
}
The question is how to test function publicFun() using Mockito, PowerMock or other testing tool ? To run this public function I have to mock private List but how can I do it ?
In this example there are several problems caused by unwelcome dependencies:
1 new Date()
To solve it I suggest to introduce new interface
interface CurrentTimeProvider {
Date getCurrentDate();
}
Implementation is obvious (I skip it for briefness)
2 Is new ArrayList()
You can replace it with you own interface (containing only method you
need)
You can mock ArrayList itself
You can use real impl of ArrayList and test it altogether
In result we get something like this:
class Some {
private CurrentTimeProvider timeProvider;
private ArrayList<SomeObject> list = new ArrayList<SomeObject>();
public void setTimeProvider(CurrentTimeProvider timeProvider) {
this.timeProvider = timeProvider;
}
public void addToList(Long t) {
SomeObject so = new SomeObject(timeProvider.getCurrentDate(), t)
list.add(so)
}
public float publicFun() {
//some other operations on private list "list"
return fun1(list);
}
And test look look this:
CurrentTimeProvider timeProvider = mock(CurrentTimeProvider.class);
Some some = new Some();
some.setTimeProvider(timeProvider);
when(timeProvider.getCurrentDate).thenReturn(mock(Date.class));
//Invoke you method
some.publicFun();
//Put assert and verify here
Basically, i have a class where i have my arrays in, which is like this
public final class DepotDatabase {
private Driver[] arrayDrivers;
public DepotDatabase() {
arrayDrivers = new Driver[4];
arrayDrivers[0] = new Driver(1234, 1234, 0); // sample driver
arrayDrivers[1] = new Driver(4444, 4444, 0); // sample driver
arrayDrivers[2] = new Driver(1337, 1337, 1); // sample manager
arrayDrivers[3] = new Driver(1234, 1234, 0); // sample driver
}
and i want to print this array in another class, i did set up the array in another class
public Driver(int username, int password, int managerCheck) {
this.username = username;
this.password = password;
this.managerCheck = managerCheck;
}
but now i want to be able to print out all the drivers, but in another class which will be called ViewDrivers or something similar
You can create a method inside DepotDatabase to print the array, then create an object from and call print method.
public final class DepotDatabase {
private Driver[] arrayDrivers;
public void printArray() {
for (int i = 0; i < arrayDrivers.length; i++) {
Driver d = arrayDrivers[i];
System.out.println("Username : " + d.getUsername());
System.out.println("Password : " + d.getPassword());
System.out.println(" Manager Check: " + d.getManagerCheck());
}
}
the from the test class you can do:
public void execute() {
DepotDatabase ddb = new DepotDatabase();
ddb.printArray();
}
That's why you'll need to have getters and setters. You should have:
public Driver[] getDrivers() {
return arrayDrivers;
}
and in the other class, you simply call it (and print it or whatever).
Read this tutorial.
If you plan to print your array in another class you show create an accessor to it.
The common pattern for Java is to use "get plus name off attribute", getDrivers() you should also avoid the class name in such geter as it may changed due to application life.
public final class DepotDatabase {
//your code
public Driver[] getDrivers() {
return this.arrayDrivers;
}
}
Next question to answer is a returning the whole array is good idea. When you return it as above you loose control on it. And every one that call that method will be able to change the content of it.
To prevent this you should use so called Defensive copying
public Driver[] getDrivers() {
return Arrays.copyOf(arrayDrivers, arrayDrivers.length);
}
Then person will get an copy of it an will not harm your class.
The issue with this is that consumer of your class will have to call this method every time to get fresh list of cars.
To solve this issue you may want to user the [collection framework] where instead of array you cold define:
List<Driver> drivers new ArrayList<>();
and provide the drivers as [immutable] list
public Iterable<Driver> getDrivers() {
return java.util.Collections.unmodifiableList(drivers);
}
Iterable is an interface, that allow you to obtain an interator the the list consumer of class wold have possibility to traverse it. IF you wan to allow him to check that list contains some driver you can set the return type as Collection
class Storage {
private String items[] = new String[10];
public String[] getItems() {
return Arrays.copyOf(items, items.length);
}
}
class Store {
Storage storage = new Storage();
private void printStorage() {
String[] items = storage.getItems();
for (String item : items) {
}
}
}
My add to hashtable method fails, what have i done wrong? Or what have i missunderstood?
test:
#Test
public void testAddKeyValue() {
AdminController cont = new AdminController();
Apartment o1 = new Apartment(1, 4, "Maier B", true);
ArrayList<Expense> exp = new ArrayList<>();
cont.addKeyWithList(o1, exp);
assertTrue(cont.isEmpty()); // ISSUE > the test works if it is true, but it is supposed be False.
}
repo class:
public class Repository extends HashMap<Apartment, ArrayList<Expense>>{
private Map<Apartment,ArrayList<Expense>> dic; // last expense object refers to curret month
Iterator<Map.Entry<Apartment, ArrayList<Expense>>> it;
public void addKeyWithList(Apartment apt, ArrayList<Expense> exp){
dic.put(apt, exp);
}
}
Why is my test not working? Or where in the code have I done something wrong?
Don't extend HashMap as you're doing. Use a HashMap and delegate to it:
public class Repository {
private Map<Apartment, List<Expense>> dic = new HashMap<Apartment, List<Expense>>();
public void addKeyWithList(Apartment apt, ArrayList<Expense> exp){
dic.put(apt, exp);
}
public boolean isEmpty() {
return dic.isEmpty();
}
}
At the moment, Repository is a HashMap, but you don't store anything in it: you store the values in another HashMap contained in Repository.
Also, storing an iterator in a field is a bad idea. iterators can be used only once. Once they have iterated, the can't iterate anymore. It should be a local variable.