-1

I am having problems instantiating a general HashMap with constant values. I intend to track inventory of various car types in a car rental service; with car type serving as key and num available to rent as the value. I attempted using a method createAvailable cars which initializes the map to constants for max number of each car type. For further testing I included a setMaxCarsAvailable method as well. Despite all this I get a NullPointer Exception coming from my canReserveVehicle method enter image description hereon the line specifying that if there are 0 available cars then you can't reserve a vehicle. How do I properly handle inventory with my map of cars? Where should I place it? I tried using a static method and later including it in a constructor with no luck. See my code below.. (I have included a picture of the stack trace showing the errors in the testCase class. I hope all this extra info helps)

public class CarReservationController {
String phoneNumber; 
long numDays = 0; 
Vehicle vehicle;
VehicleType vType;

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 

public static final int MAX_ECONOMY = 10; //used this to track the amount of cars available to rent. This was applied in the canReserveVehicle and addReservation methods
public static final int MAX_PREMIUM = 10; 
public static final int MAX_SUV = 5;

public CarReservationController()
{
    availableCars = createAvailableCarsMap(); //this is my attempt at instantiating my availableCars map to contain (VehicleType.ECONOMY, 10), (VehicleType.PREMIUM, 10), map.put(VehicleType.SUV, 5); ;
}

Map<VehicleType, Integer> availableCars; 
Map<VehicleType, PriorityQueue<Date>> reservedVehicleReturnDates = new HashMap<>(); // Map from vehicle type to reserved car end dates. This will hold all the current reservations end dates for each vehicle type
//was public static map
public HashMap<String, List<CarReservation>> reservationsMap = new HashMap<>();
//previously private static Map... 
private Map<VehicleType, Integer> createAvailableCarsMap() {
    Map<VehicleType, Integer> map = new EnumMap<VehicleType, Integer>(VehicleType.class);
    map.put(VehicleType.ECONOMY, MAX_ECONOMY);
    map.put(VehicleType.PREMIUM, MAX_PREMIUM);
    map.put(VehicleType.SUV, MAX_SUV);
    return map;
}



public void setMaxCarsAvailable(VehicleType v, int maxAvailable) {
        availableCars.put(v, maxAvailable);
}

//I UPDATE carReservationsMap here..this adds an actual reservation but first it checks the boolean canReserveVehicle below
public void addReservation(CarReservation res) throws Exception //right here
{   

    Date sDate = res.getStartDate(); //HERE
    Date eDate = res.getEndDate(); //HERE
    String phoneNumber = res.getPhoneNumber();
        if(canReserveVehicle(vType, phoneNumber, sDate, eDate)) {
            if (reservationsMap.containsKey(phoneNumber)) {
                List<CarReservation> currCustomerRes = reservationsMap.get(phoneNumber);
                currCustomerRes.add(res);
                reservationsMap.put(phoneNumber, currCustomerRes);
            } else {
                List<CarReservation> currCustomerRes = new ArrayList<CarReservation>(Arrays.asList(res));
                reservationsMap.put(phoneNumber, currCustomerRes);
            }
            int countForVehicleType = availableCars.get(vType);
            availableCars.put(vType, countForVehicleType - 1);
            if (reservedVehicleReturnDates.containsKey(vType)) {
                reservedVehicleReturnDates.get(vType).add(eDate);
            } else {
                PriorityQueue<Date> q = new PriorityQueue<Date>();
                reservedVehicleReturnDates.put(vType, q);
            }
        }   
}

//NULL POINTER EXCEPTION COMING UP HERE FROM JUNIT TESTS
public boolean canReserveVehicle(VehicleType v, String phoneNumber, Date startDate, Date endDate) throws ParseException 
{
    PriorityQueue<Date> reservedVehicleQueue = reservedVehicleReturnDates.get(v);
    if(endDate.before(startDate))
        return false; // check that the start date of the reservation is before the end date 

    if (availableCars.get(v) == 0) { /// SAYS THERE IS A NULL POINTER EXCEPTION from here... because availableCars is still 0..
        Date nextCarReturnDate = reservedVehicleQueue.peek();
        if(nextCarReturnDate.after(startDate))
            return false; // return false if a reserved car is not going to be available before the new customer is requesting one.
    }
    else {
        // If a car that will become available before the customer requests it, remove it from the queue and replace with the 
        //requesting customer's return date (as they now lay claim to the car)
        reservedVehicleQueue.poll();
        reservedVehicleQueue.add(endDate);
    }

    //these are comparing strings.
    if (reservationsMap.containsKey(phoneNumber)) {
        List<CarReservation> resByCustomer = reservationsMap.get(phoneNumber);
        CarReservation lastResByCustomer = resByCustomer.get(resByCustomer.size() - 1); 
        Date lastResEndDate = sdf.parse(lastResByCustomer.endDate);
        if (startDate.before(lastResEndDate)) {  //1 customer can only have one rental at a time within the system.
            return false;
        } 
    }
    return true;    
}

}

Test case looks like this with "java.lang.NullPointerException" CarReservationController.canReserveCarVehicle"

import java.text.SimpleDateFormat;

import org.junit.Test;

public class CarReservationTest {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 


@Test
public void testThatCustomerCanMakeReservation() throws Exception {
    CarReservationController reservationSystem = new CarReservationController();
    reservationSystem.setMaxCarsAvailable(VehicleType.PREMIUM, 2);
    CarReservation firstRes = new CarReservation(VehicleType.PREMIUM, "Jon Snow", "1234567890", "2019-01-23", "2019-01-31");
    reservationSystem.addReservation(firstRes);
    //assertTrue(reservationSystem.reservationsMap.containsKey("1234567890"));
    assertTrue(reservationSystem.reservationsMap.size() > 0);
    assertEquals(firstRes, reservationSystem.reservationsMap.get("1234567890"));
}
}
user6952090
  • 65
  • 1
  • 8
  • Where are you adding values to `reservationsMap`? – nabster Feb 12 '19 at 16:31
  • Please provide full exception stack trance, from where you are calling `canReserveVehicle`? Also don't write stack trace manually please copy paste it so you don't have typo. – Jainik Feb 12 '19 at 16:33
  • Hi @Janik I included the image of the stack trace as well as the addReservation method which gives more context to the canReserveVehicle – user6952090 Feb 12 '19 at 17:03
  • @nabster that happens in the addReservation method which I have included in the edit. Let me know if you need more info. – user6952090 Feb 12 '19 at 17:04
  • @Andy Turner why is it getting marked as duplicate when it is not helping the question? – user6952090 Feb 13 '19 at 03:56

1 Answers1

0

There are several issues that make this complicated to debug.

Perhaps most important for the question you asked, without a full stacktrace, it isn't obvious whether the NPE you are seeing is from availbleCars.get(v) or from availableCars.get(v) == 0.

That issue is complicated by the fact that without knowing what the ReservationSystem::addReservation method does, I don't think it's possible to rule out either possibility.

Possibility 1

However, if the issue is from availableCars.get(v) == 0, then it might be from your choice to compare equality between an Integer and a numeric primitive using == instead of .equals(). Please see this previous answer for a more complete discussion: Why comparing Integer with int can throw NullPointerException in Java?

Possibility 2

If the issue is from availableCars.get(v) (that availableCars itself is null), then you may have an issue with how you are instantiating that availableCars map. The method you are using there doesn't need to be static, and also you don't need the setter you have created.

Next Steps

To solve this problem, I'd recommend using a breakpoint or breaking that comparison into two steps with debug statements - first check to see that availableCars is not null, then check that availableCars.get(v) is an Integer, and then use .equals() to check the equality with 0.

In addition, you might try unit testing your methods to instantiate the availableCars map and the ReservationSystem::addReservation method separately as well, to help narrow down where the bug might be.

theonlyrao
  • 416
  • 2
  • 13
  • Good catch with Integer countForVehicleType = availableCars.get(vType);I changed that to int instead. I removed the static keyword from createAvailableCarsMap() too but still getting NullPointerException. stemming fromavailableCars.get(v) == 0. I guess this comes back to my original question, how do I properly populate my availableCarsMap.. Enlighten me on the proper syntax. – user6952090 Feb 12 '19 at 18:38