7

Using of Collections.emptyList() the right way in Java 1.5+

Posted by JOKe on 7/27/2010 04:07:00 PM

It is little strange that no one really uses emptyList like he should in Java.
So this is small post showing how to use the emptyList method in the Collections class.

Question: How to create an empty list ?
lets assume that we have a class Book with multiple titles.
So the class in our examples will be:

import java.util.List;

public class Book {

      private List<String> titles;

      public void setTitles(List<String> titles) {

            this.titles = titles;

      }

      public List<String> getTitles() {

            return titles;

      }

}

Lets say that in our snippet we have something like :

  Book myCrazyBook=new Book();

and we want to assign an empty list to the titles in this book. This is a common scenario if you want to set something to be emptyList in specific case instead of null.

So of course your first try will be something like:
Answer 1:

  myCrazyBook.setTitles(new ArrayList()); 

-WARRNING - ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized

Ok changing to:

  myCrazyBook.setTitles(new ArrayList<String>());   

WTF ? the problem in this answer is not small one :
- you are creating empty ArrayList which basiclly is not needed. ( what if you are in a loop 1000+ empty ArrayLists ? )

Answer 2.

   myCrazyBook.setTitles(Collections.EMPTY_LIST);

-WARNING : Type safety: The expression of type List needs unchecked conversion to conform to List<String>, because the EMPTY_LIST is raw type, which was heavily used before Java 1.5.
The definition of this list is :

    /**

     * The empty list (immutable).  This list is serializable.

     *

     * @see #emptyList()

     */

    public static final List EMPTY_LIST = new EmptyList();

So you see it is not ArrayList or LinkedList or MyCrazyCustomListWhichIUseEveryWhereList.

Answer 3:
Eclipse will tell you this answer : Replace with Collections.emptyList();

      myCrazyBook.setTitles(Collections.emptyList());

COMPILE TIME ERROR: why ? because emptyList invoked like that means List of Objects not List of String. The other thing is that you cannot cast to List<String> because you cannot cast List<Object>  to List<String>.

Answer 4:
You know that there is Collections.emptyList() AND YOU KNOW THAT IT RETURNS List<T>
so your answer is:

            Book myCrazyBook=new Book();

            List<String> titles = Collections.emptyList();

            myCrazyBook.setTitles(titles);

           

And this will work WITHOUT any WARNINGS or ERRORS. The type of the List is taken from the type of the variable that you are trying to assign to.
Of course why you need this local variable ? I want to remove it it is not needed and used, but if you remove it you are in Answer 3. So what can you do ?

Answer 5: The right but strange looking answer.

            Book myCrazyBook=new Book();

            myCrazyBook.setTitles(Collections.<String>emptyList());

Yes this is not a joke there is a dot (.) then the generic type before the method name. This compiles, runs, no warnings thats the real way.
It is a little strange that most people dont know this aspect of generics in Java even I didn't know it, I was thinking that you cannot pass a generic type like this but as it looks you can.

So if you have some static method like this one:

public class Main{

      public static <G> List<G> someGreatMethod(){

            List<G> gList= new ArrayList<G>();

            return gList;

      }

}

you can invoke it with Main.<String>someGreatMethod(); for example.

|
4

Spring MVC, Spring Bean Validation Framework and validating confirm password / confirm email fields.

Posted by JOKe on 6/29/2010 12:19:00 PM

How to write validation like confirm password, confirm email and etc in Spring MVC.

NOTE: To make bean validation to work its nice to read this tutorial: <a href="http://wheelersoftware.com/articles/spring-bean-validation-framework.html"></a>

Today I was busy making some validations and implementations on very common scenario:
change email and password.
So we have a new password AND a new email also for both of them we have a confirm email/password field. And we want to validate everything nicely and to show to the user the real validation message if there is some error.
So ... I've to use a form which already uses some annotations like @NoBlank and etc I think everyone of you is using annotations framework if you don't use it SHAME ON YOU !:)


Anyway so I've added some fields to existing form bean:

private String newPassword;
private String confirmNewPassword;
private String newEmail;
private String confirmNewEmail;

Basiclly in my case this is very big form and none of this fields is mendatory so the user can leave all of them blank. My first idea was to add at least Length for the password and Email annotations for the email so I do:

@Length(min=6,max=20)
private String newPassword;
private String confirmNewPassword;
@Email
private String newEmail;
private String confirmNewEmail;

Ok but the confirm fields should have the same rules ? Maybe...
The problem that I saw is that length and email by default means NotBlank.
To make email validator to work or length validator they first check is the field blank. In my case I want the blank to be OK.. so I asked god google what to do.
The answer applyIf.
So at the end I get :

@Length(min = 6, max = 20, applyIf = "newPassword is not blank") //cool right ?
private String newPassword;
private String confirmNewPassword;
@Email(applyIf = "newEmail is not blank") //cool right ?
private String newEmail;
private String confirmNewEmail;

Cool right ? yep it is cool. but let me add the validation for confirmNewPassword and confirmNewEmail.

@Length(min = 6, max = 20, applyIf = "newPassword is not blank")
private String newPassword;
@NotBlank(applyIf = "newPassword is not blank")
private String confirmNewPassword;

@Email(applyIf = "newEmail is not blank")
private String newEmail;
@NotBlank(applyIf = "newEmail is not blank")
@Email(applyIf = "newEmail is not blank")
private String confirmNewEmail;

Nice.. so I have validation on new* fields only if they are not blank. Also I have a validation on the confirm fields only if again new* fields are not blank.
Cool... what left ? ahh the most hard part to check is the confirmpassword the same as the newPassword and is the confirmEmail same as the newEmail.

the first idea ofcourse is to write a custom validator.
So I write this :

class NewPassAndEmailValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return PersonalDetailsFormBean.class.equals(clazz);
    }

    @Override
    public void validate(Object obj, Errors errors) {
        PersonalDetailsFormBean personalDetailsFormBean = (PersonalDetailsFormBean) obj;
        if (personalDetailsFormBean.getNewPassword() != null
                && !personalDetailsFormBean.getNewPassword().equals("")) {
            if (!personalDetailsFormBean.getNewPassword().equals(personalDetailsFormBean.getConfirmNewPassword())) {
                errors.rejectValue("confirmNewPassword", "PersonalDetailsFormBean.confirmNewPassword[customvalidator]");
            }
        }
        if (personalDetailsFormBean.getNewEmail() != null && !personalDetailsFormBean.getNewEmail().equals("")) {
            if (!personalDetailsFormBean.getNewEmail().equals(personalDetailsFormBean.getConfirmNewEmail())) {
                errors.rejectValue("confirmNewEmail", "PersonalDetailsFormBean.confirmNewEmail[customvalidator]");
            }
        }
    }

}

and then in the controller submit method.

validator.validate(personalDetailsFormBean, result); //this invokes the annotation based validator.

NewPassAndEmailValidator newPassAndEmailValidator = new NewPassAndEmailValidato();
newPassAndEmailValidator.validate(personalDetailsFormBean, result);

if (result.hasErrors()) {
... return...
}

This .... WORKS FINE. BUT... ah its not cool :( ... I mean even in struts 1 in 2001 we ware having a validation based on expression. AND we have even better way here... Awesome :D

So I've removed this validator... and write only "this":

@Expression(value = "confirmNewPassword = newPassword", applyIf = "newPassword is not blank")

So the final example looks like this:

@Length(min = 6, max = 20, applyIf = "newPassword is not blank")
private String newPassword;
@NotBlank(applyIf = "newPassword is not blank")
@Expression(value = "confirmNewPassword = newPassword", applyIf = "newPassword is not blank")
private String confirmNewPassword;

@Email(applyIf = "newEmail is not blank")
private String newEmail;
@NotBlank(applyIf = "newEmail is not blank")
@Email(applyIf = "newEmail is not blank")
@Expression(value = "confirmNewEmail = newEmail", applyIf = "newEmail is not blank")
private String confirmNewEmail;

:) ok this looks cool :D maybe not so cool than 20+ if statements to checks for null for some of you to but I like this way :))


|

Copyright © 2009 JOKe's Blog All rights reserved. Theme based on the Theme by Laptop Geek with changes by JOKe. | Bloggerized by FalconHive.