3

I'm trying to develop a Card Validation program in Java. The isCardValid method basically checks if a given Card number is valid or not. I have specified a condition there that should throw an IllegalArgumentException, but it doesn't & the program successfully executes with exit code 0

Following is my Java file: -

public class CardValidation {

  public static String getCardBrand(final String cardIsin){


        String brand = null;

        if (cardIsin == null || cardIsin.equals("")){
            log.warn("Given card BIN is null!! So returning null");
            return brand;
        }


        if (cardIsin.substring(0,2).matches("51|52|53|54|55"))
            brand = "MasterCard".toUpperCase();
        else if (cardIsin.startsWith("4"))
            brand = "Visa".toUpperCase();
        else if (cardIsin.startsWith("34") || cardIsin.startsWith("37"))
            brand = "Amex".toUpperCase();
        else if (Pattern.matches(maestroPattern,cardIsin))
            brand = "Maestro".toUpperCase();
        else if (Pattern.matches(diners, cardIsin))
            brand = "Diners".toUpperCase();
        else if (Pattern.matches(discover,cardIsin))
            brand = "Discover".toUpperCase();
        else if (doesFallInRupayRange(cardIsin))
            brand = "Rupay".toUpperCase();
        else if (cardIsin.startsWith("35"))
            brand = "JCB";

        return brand;
    }

  public static boolean isCardValid(final String cardNumber){

        if(cardNumber.matches("[^0-9]"))
            throw new IllegalArgumentException("INVALID ARGUMENT!!!! Card number should contain ONLY digits.");

        String cardBrand = getCardBrand(cardNumber);

        if (cardBrand == null)
            return false;
        if(cardBrand.equalsIgnoreCase("VISA") || cardBrand.equalsIgnoreCase("MasterCard") ||
                cardBrand.equalsIgnoreCase("DISCOVER") || cardBrand.equalsIgnoreCase("RUPAY")) {
            return cardNumber.length() == 16;
        }
        else if(cardBrand.equalsIgnoreCase("AMEX")) {
            return cardNumber.length() == 15;
        }
        else if(cardBrand.equalsIgnoreCase("MAESTRO")) {
            return cardNumber.length() == 16 || cardNumber.length() == 19;
        }
        else if(cardBrand.equalsIgnoreCase("DINERS")) {
            return cardNumber.length() == 14;
        }
        log.info("Unknown card number brand: " + cardNumber);
        return cardNumber.length() >= 12;
    }

public static boolean doesFallInRupayRange(final String isin){

       long intIsin = Long.parseLong(isin.replaceAll("[^\\d]", "").substring(0,6));

        for (int row = 0; row < CardValidation.rupayRange.length; row++)
        {
            try {
                if (intIsin >= CardValidation.rupayRange[row][0] && intIsin <= CardValidation.rupayRange[row][1])
                    return true;
            }
            catch (Exception e) {
                log.error("Error while checking for RuPay: " + isin, e);
            }
        }
        return false;
    }

    public static void main (String... args){
        CardValidation.isCardValid("42424242hghghghgh");
    }
}

Now the following code snippet should throw the mentioned Exception, shouldn't it, since I'm deliberately supplying an invalid argument to the method from my main?

 if(cardNumber.matches("[^0-9]"))
            throw new IllegalArgumentException("INVALID ARGUMENT!!!! Card number should contain ONLY digits.");

The following is the output I get in my console

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

Process finished with exit code 0
Auro
  • 1,578
  • 3
  • 31
  • 62

1 Answers1

4

Your regular expression is wrong.

Try this instead:

String regex = "\d+";

Or alternatively:

String regex = "[0-9]+";

Therefore the invalid number isn't matched; therefore no exception.

In order to use the above patterns, you have to invert the logic:

if ( ! input.matches(regex) ) {
  throw exception

But please note: your code is "not good". For example: you are not using any kind of abstraction. You are representing credit card types as Strings. That's like super-bad. Because every piece of code dealing with different credit cards ... will have to know that "AMEX" means "american express; and so on. Consider using an Enum instead.

In other words: you really want to read/learn about doing good Object Oriented designs!

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • What I'm trying to do here is, check if the `cardNumber` that is a `String` contains anything more than just digits. Shouldn't the given expression **[^0-9]** work? And thank you for your suggestion, I will change them to enum – Auro Aug 12 '16 at 08:23
  • 2
    That is what I am telling you: my patterns **match** if the input contains only digits. Yours does not. Simply study the rules for regular expressions to figure why that is! – GhostCat Aug 12 '16 at 08:25
  • 1
    @Auro A good way to play around and learn regex is [RegExr](http://www.regexr.com) – Andreas Brunnet Aug 12 '16 at 08:27