Close

Spring - Session based Prototype Bean Example

[Last Updated: Jun 12, 2021]

Following example shows how prototype bean can contain a session information.

Example

This example creates a registration form simulator. It asks user to enter registration information on command line. It does some validations on entered values and keep the same prototype bean session (UserRegistrationBean) unless user successfully correct all validation errors.

A POJO contains user info

package com.logicbig.example.service;

public class UserInfo {
  private String email;
  private String password;
    .............
}

User info Validator

package com.logicbig.example.bean;

import java.util.regex.Pattern;

public class UserRegistrationValidator {

  private static final Pattern VALID_EMAIL_PATTERN =
          Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$",
                  Pattern.CASE_INSENSITIVE);

  private static final Pattern VALID_PASSWORD_PATTERN =
          Pattern.compile("^[a-zA-Z0-9]{6,}$");

  public String validateEmail(String email){
      if (!VALID_EMAIL_PATTERN.matcher(email).matches()) {
          return "Not a valid email: " + email;
      }
      return null;
  }

  public String validatePassword(String password){
      if (!VALID_PASSWORD_PATTERN.matcher(password).matches()) {
          return "Not a valid password. The password should  be alphanumeric and " +
                  "at least 6 characters long ";
      }
      return null;
  }
}

Registration Service

package com.logicbig.example.service;

public interface RegistrationService {

  void register(UserInfo userInfo);
}

Registration Service implementation

public class RegistrationServiceImpl implements RegistrationService {


  @Override
  public void register(UserInfo userInfo) {
      //todo: save user in a database
  }
}

Registration service client bean

package com.logicbig.example.bean;

import com.logicbig.example.service.UserInfo;
import java.util.Map;

public interface UserRegistrationBean {
  public static String KEY_EMAIL = "email";
  public static String KEY_PASSWORD = "password";

  void setUserInfo(UserInfo userInfo);

  Map<String, String> validate();

  void register();

}
package com.logicbig.example.bean;

import com.logicbig.example.service.RegistrationService;
import com.logicbig.example.service.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;
import java.util.Map;

public class UserRegistrationBeanImpl implements UserRegistrationBean {

  @Autowired
  private RegistrationService registrationService;
  @Autowired
  private UserRegistrationValidator validator;

  private UserInfo userInfo;

  @Override
  public void setUserInfo (UserInfo userInfo) {
      this.userInfo = userInfo;
  }

  @Override
  public Map<String, String> validate () {
      if (userInfo == null) {
          throw new RuntimeException("UserInfo must be set before calling validate method");
      }

      Map<String, String> errors = new LinkedHashMap<>();

      String errorMessage = validator.validateEmail(userInfo.getEmail());
      if (errorMessage != null) {
          errors.put(KEY_EMAIL, errorMessage);
      }

      errorMessage = validator.validatePassword(userInfo.getPassword());
      if (errorMessage != null) {
          errors.put(KEY_PASSWORD, errorMessage);
      }

      return errors;
  }

  @Override
  public void register () {
      registrationService.register(userInfo);
  }
}

Defining beans

package com.logicbig.example;


import com.logicbig.example.bean.UserRegistrationBean;
import com.logicbig.example.bean.UserRegistrationBeanImpl;
import com.logicbig.example.bean.UserRegistrationValidator;
import com.logicbig.example.service.RegistrationService;
import com.logicbig.example.service.RegistrationServiceImpl;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;


@Configuration
public class Config {

  @Bean
  public UserRegistrationValidator validator () {
      return new UserRegistrationValidator();
  }

  @Bean
  public RegistrationService registrationService () {
      return new RegistrationServiceImpl();
  }

  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  @Bean
  public UserRegistrationBean userRegistrationBean () {
      return new UserRegistrationBeanImpl();
  }
}

Main class

package com.logicbig.example;

import com.logicbig.example.bean.UserRegistrationBean;
import com.logicbig.example.service.UserInfo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.io.InputStream;
import java.io.PrintStream;
import java.util.Map;
import java.util.Scanner;

public class AppMain {
  private final PrintStream printStream;
  private Scanner scanner;

  public AppMain(InputStream inputStream, PrintStream printStream) {
      this.scanner = new Scanner(inputStream);
      this.printStream = printStream;
  }

  public static void main(String[] args) {
      AppMain appMain = new AppMain(System.in, System.out);
      appMain.start();
  }

  public void start() {
      AnnotationConfigApplicationContext context =
              new AnnotationConfigApplicationContext(Config.class);
      UserRegistrationBean registrationBean = context.getBean(UserRegistrationBean.class);
      while (true) {
          printStream.println("UserRegistrationBean, instance: " + System.identityHashCode(registrationBean));
          printStream.println("Enter new user. Enter exit to terminate");
          boolean exit = registerUser(registrationBean);
          if (exit) {
              break;
          }
          registrationBean = context.getBean(UserRegistrationBean.class);
      }
  }

  private  boolean registerUser(UserRegistrationBean registrationBean) {
      UserInfo userInfo = new UserInfo();
      registrationBean.setUserInfo(userInfo);
      Map<String, String> errors = null;
      while (errors == null || errors.size() > 0) {
          if (errors != null) {
              printStream.println("Errors : " + errors.values() + "\n");
              printStream.println("Please enter exit to terminate");
          }

          if (errors == null || errors.containsKey(UserRegistrationBean.KEY_EMAIL)) {
              String email = getUserInput("Enter Email");
              if (email == null) {
                  return true;
              }
              userInfo.setEmail(email);
          }
          if (errors == null || errors.containsKey(UserRegistrationBean.KEY_PASSWORD)) {
              String password = getUserInput("Enter Password");
              if (password == null) {
                  return true;
              }
              userInfo.setPassword(password);
          }

          errors = registrationBean.validate();
      }
      registrationBean.register();
      printStream.println("User has been registered successfully: "+userInfo);
      return false;
  }

  public  String getUserInput(String instruction) {
      printStream.print(instruction + ">");
      String s = scanner.nextLine();
      if ("exit".equals(s)) {
          return null;
      }
      return s;

  }
}

Output

UserRegistrationBean, instance: 1089504328
Enter new user. Enter exit to terminate
Enter Email>xyz
Enter Password>123
Errors : [Not a valid email: xyz, Not a valid password. The password should  be alphanumeric and at least 6 characters long ]

Please enter exit to terminate
Enter Email>joe@example.com
Enter Password>123456
User has been registered successfully: UserInfo{email='joe@example.com', password='123456'}
UserRegistrationBean, instance: 660879561
Enter new user. Enter exit to terminate
Enter Email>joe2@example.com
Enter Password>987654
User has been registered successfully: UserInfo{email='joe2@example.com', password='987654'}
UserRegistrationBean, instance: 1485697819
Enter new user. Enter exit to terminate
Enter Email>exit

Note that how new instance of UserRegistrationBean (the prototype bean) is created on each call of context.getBean(UserRegistrationBean.class)

Example Project

Dependencies and Technologies Used:

  • spring-context 5.3.8: Spring Context. Version Compatibility: 3.2.3.RELEASE - 5.3.8 Version List
    ×

    Version compatibilities of spring-context with this example:

    • 3.2.3.RELEASE
    • 3.2.4.RELEASE
    • 3.2.5.RELEASE
    • 3.2.6.RELEASE
    • 3.2.7.RELEASE
    • 3.2.8.RELEASE
    • 3.2.9.RELEASE
    • 3.2.10.RELEASE
    • 3.2.11.RELEASE
    • 3.2.12.RELEASE
    • 3.2.13.RELEASE
    • 3.2.14.RELEASE
    • 3.2.15.RELEASE
    • 3.2.16.RELEASE
    • 3.2.17.RELEASE
    • 3.2.18.RELEASE
    • 4.0.0.RELEASE
    • 4.0.1.RELEASE
    • 4.0.2.RELEASE
    • 4.0.3.RELEASE
    • 4.0.4.RELEASE
    • 4.0.5.RELEASE
    • 4.0.6.RELEASE
    • 4.0.7.RELEASE
    • 4.0.8.RELEASE
    • 4.0.9.RELEASE
    • 4.1.0.RELEASE
    • 4.1.1.RELEASE
    • 4.1.2.RELEASE
    • 4.1.3.RELEASE
    • 4.1.4.RELEASE
    • 4.1.5.RELEASE
    • 4.1.6.RELEASE
    • 4.1.7.RELEASE
    • 4.1.8.RELEASE
    • 4.1.9.RELEASE
    • 4.2.0.RELEASE
    • 4.2.1.RELEASE
    • 4.2.2.RELEASE
    • 4.2.3.RELEASE
    • 4.2.4.RELEASE
    • 4.2.5.RELEASE
    • 4.2.6.RELEASE
    • 4.2.7.RELEASE
    • 4.2.8.RELEASE
    • 4.2.9.RELEASE
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8

    Versions in green have been tested.

  • junit 4.13.2: JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.
  • JDK 8
  • Maven 3.8.1

Session based Prototype Bean Example Select All Download
  • spring-scopes
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • bean
                • service
                • AppMain.java
        • test
          • java
            • com
              • logicbig
                • example

    See Also