3

I get javax.faces.FacesException: java.lang.NullPointerException when I type something in the zip code and hit submit with country set to default null value. If I select the country and then type something everything works. I tried SubmittedValue, but it is working the opposite way - with null is working and after this is giving null exception.

@FacesValidator("zipV")
public class ZipValidator implements Validator {

LocaleBean Bean = new LocaleBean();
String language;
private static final String ZIP_PATTERN_BG = "\\d{4}";
private static final String ZIP_PATTERN_US = "\\d{5}";
private static final String ZIP_PATTERN_DEFAULT = "[A-Za-z0-9]*";
private String zip_pattern;
private Pattern pattern;
private Matcher matcher;
private String country;


@Override
public void validate(FacesContext context, UIComponent component, Object value) throws       ValidatorException {

    language = Bean.getLanguage();

    UIInput Input = (UIInput) component.getAttributes().get("country");
    country = Input.getValue().toString();
    String zip = (String) value;


    if (country == null || country.isEmpty()) {
        return; 
    }

    switch (country) {
        case "BGR":
            zip_pattern = ZIP_PATTERN_BG;
            break;
        case "USA":
            zip_pattern = ZIP_PATTERN_US;
            break;
        default:
            zip_pattern = ZIP_PATTERN_DEFAULT;
            break;
    }

    pattern = Pattern.compile(zip_pattern);

    matcher = pattern.matcher(value.toString());
    if (!matcher.matches()) {


        switch (language) {
            case "en": {
                FacesMessage msg = new FacesMessage("Invalid zip.");
                msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                throw new ValidatorException(msg);
            }
            case "bg": {
                FacesMessage msg = new FacesMessage("Невалиден пощенски код.");
                msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                throw new ValidatorException(msg);
            }
        }
    }
}
}

Here's the view:

<h:selectOneMenu id="country" value="#{account.country}" required="true" requiredMessage="#{msg['register.required']}" binding="#{country}">
<f:selectItem itemValue="#{null}" itemLabel="#{msg['register.countryQ']}"/>
<f:selectItems value="#{account.countries}"/>
<f:ajax listener="#{account.loadStates()}" render="state"/>
</h:selectOneMenu>

<h:inputText id="zipcode" required="true" requiredMessage="#{msg['register.required']}" value="#{account.zipcode}">
<f:validator validatorId="zipV"/>
<f:attribute name="country" value="#{country}"/>
</h:inputText>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Pavel
  • 1,278
  • 2
  • 17
  • 34
  • is the null pointer on Input.getValue().toString() ? – Jonathan Viccary Sep 06 '13 at 16:58
  • yes, if I change it to SubmittedValue, it is working with null and not working after this. – Pavel Sep 06 '13 at 17:03
  • could you explain what you mean by 'after this'? do you mean if you use Input.getSubmittedValue().toString() then you don't get the null pointer, but the code doesnt work somewhere after this point? – Jonathan Viccary Sep 06 '13 at 17:06
  • I type a value in the zip form, and I click submit - I do not get a nullpointer. I change the country, and I click submit - I get the null pointer. – Pavel Sep 06 '13 at 17:11
  • The `getSubmittedValue()` is not the right approach. You should only use it if the validator runs *before* the component is been processed. This is not the case here. The validator is running on the zip component *after* the country component is been processed. – BalusC Sep 06 '13 at 17:19

1 Answers1

2

Here,

country = Input.getValue().toString();

you should not be using toString() at all. You should be casting it:

country = (String) Input.getValue();

Otherwise it will throw NullPointerException if the getValue() returned null. As its javadoc clearly says, a NullPointerException will be thrown among others when you attempt to call an instance method on null (like as you did with toString()).

Please note that this problem is technically unrelated to JSF. It's just basic Java. The java.lang package of the exception is a very good hint in this. If you got an exception of javax.faces (or javax.el) package, then we can talk about a true JSF (or EL) problem.

See also:


Unrelated to the concrete problem, I'd really respect Java naming conventions. Variable names start with lowercase. Use input instead of Input. Also, your manual control of localization is strange. What if you ever need to support 10 languages? Do you expand the switches over all place? Make use of JSF builtin localization facilities with <resource-bundle> and ResourceBundle#getBundle().

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • thanks this helped. How can I make my ResourceBundle#getBundle() to get the bundle from com.program.messages instead of the root folder. – Pavel Sep 06 '13 at 21:29
  • Just pass exactly that value as base name. – BalusC Sep 06 '13 at 21:32
  • I tried it does not work. It works only if they are called messages.properties in the root and the value is messages. ResourceBundle.getBundle("messages", currentLocale). I also tried com/program/messsages/messages... it does not work – Pavel Sep 06 '13 at 21:44