Ad

Thursday, 5 March 2015

No unique bean of type [] is defined: expected single matching bean but found 2

In this post we will see how to resolve the exception-"NoSuchBeanDefinitionException:No unique bean of type [] is defined: expected single matching bean but found 2" in spring.By using autowiring feature in spring,we can make the spring container to resolve the bean dependencies automatically and hence we don't need to declare the dependencies either through constructor arguments or through properties in the application context file.We can autowire the beans by:
  • ByName  - spring container will autowire the dependencies by looking up the bean name in the application context file which will match with the bean property name.Lets says  a bean X has the property y(has the setY method too) and the  spring container will look for the bean named "y" in the application context and inject the same to bean X.
  • ByType   - spring container will autowire the property with the bean which has the same type.If more than one bean exists in the container of the same type,then the above fatal exception is thrown
  • Constructor - Its as same as ByType,but it applies to the argument type of the bean to be autowired.If more than one bean or no bean exist in the container of the same constructor type then the above fatal exception is thrown.
Let say we have the below classes and we would like to autowire the  dependencies by type.
  • Bus - Bean class for which the container has to autowire the dependencies by type.
  • Engine - Bean class which is set as the property of the bus object.
  • BusDemo -Main class which will load the spring container and get the bus bean from the container.
  • buscontext.xml - metadata configuration details for the spring container.
Bus.java

package test;

public class Bus {
private Engine engine=null;

public Engine getEngine() {
return engine;
}

public void setEngine(Engine engine) {
this.engine = engine;
}

        @Override
public String toString() {
return "Bus [engine=" + engine + "]";
}
}
   

Engine.java

package test;

public class Engine {
private String engineMake;
private String engineCost;

public String getEngineMake() {
return engineMake;
}

public void setEngineMake(String engineMake) {
this.engineMake = engineMake;
}

public String getEngineCost() {
return engineCost;
}

public void setEngineCost(String engineCost) {
this.engineCost = engineCost;
}
       
        @Override
public String toString() {
return "Engine [engineMake=" + engineMake + ", engineCost="
+ engineCost + "]";
} 
}

buscontext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="bus" class="test.Bus" autowire="byType">
</bean>

<bean id="primaryengine" class="test.Engine">
<property  name="engineMake" value="Ford"/>
<property  name="engineCost" value="100000"/>
</bean>

<bean id="secondaryengine" class="test.Engine">
<property  name="engineMake" value="Renault"/>
<property  name="engineCost" value="50000"/>
</bean>

</beans>

As we can see in the application context file,we use the attribute autowire="byType" to make the container to automatically inject and resolve the dependencies for the bus bean.Container will look for the bean of type "test.Engine" and inject the same to the engine property of the bus bean.

BusDemo.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BusDemo {
public static void main(String[] args) {
ApplicationContext bf= new ClassPathXmlApplicationContext(new String[]  
               {"buscontext.xml"});
Bus bus= bf.getBean("bus",Bus.class);
       System.out.println(bus);
}

}

OUTPUT:

When we run the main program - BusDemo,we will get the below exception

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bus' defined in class path resource [buscontext.xml]: Unsatisfied dependency expressed through bean property 'engine': : No unique bean of type [test.Engine] is defined: expected single matching bean but found 2: [primaryengine, secondaryengine]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test.Engine] is defined: expected single matching bean but found 2: [primaryengine, secondaryengine]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType
(AbstractAutowireCapableBeanFactory.java:1167)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean
(AbstractAutowireCapableBeanFactory.java:1059)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean
(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject
(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton
(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean
(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean
(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons
(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization
(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh
(AbstractApplicationContext.java:464)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at test.BusDemo.main(BusDemo.java:9)

While autowiring the dependencies for the bus bean, container found two beans of type  test.Engine instead of one and hence this exception was thrown

We can resolve this exception either in two ways.Let say we want the container to autowire the dependency for the bus bean with the primaryengine bean.

1)Set the primary attribute of the primaryengine bean to true,so that the container will nominate this bean to inject it to the bus bean by autowiring

   <bean id="primaryengine" class="test.Engine" primary="true">
   <property  name="engineMake" value="Ford"/>
   <property  name="engineCost" value="100000"/>
   </bean>

or

2)Set the autowire-candidate attribute of the secondaryengine bean to false,so that the container will exclude this bean for autowiring  and hence inject the primaryengine bean to the bus bean. 

<bean id="secondaryengine" class="test.Engine" autowire-candidate="false">
<property  name="engineMake" value="Renault"/>
<property  name="engineCost" value="50000"/>
</bean>

Now if we run the BusDemo with the change(either option 1 or 2 as above) in the buscontext.xml,we get the below output

Bus [engine=Engine [engineMake=Ford, engineCost=100000]]

Wednesday, 4 March 2015

@ConstructorProperties annotation in spring IOC

@ConstructorProperties is used in constructor based dependency injection.It is mainly used when we need the constructor arguments passed in the application context(metadata to the spring container) should be resolved by the constructor parameter name in the bean object to be created.By annotating @ConstructorProperties in the constructor of the bean class,it will make the constructor parameter names available to the spring container at runtime.Below sample will show how this annotation can be used:
  • Person - Bean class in which container will inject the dependencies through constructor arguments
  • personcontext.xml - metadata configuration details for the spring container
  • PersonDemo - Main class which will load the spring container and get the person bean from the container.

Person.java

package test;

import java.beans.ConstructorProperties;

public class Person {
private String name;

private int age;

@ConstructorProperties({"pername", "perage"})
public Person(String pername, int perage) {
super();
this.name = pername;
this.age = perage;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}

Since we have annotated the  constructor parameters with @ConstructorProperties,the constructor parameter names(pername and perage) will be available to Spring container at runtime.

personcontext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="person" class="test.Person">
<constructor-arg  name="pername" value="Ram"/>
<constructor-arg  name="perage" value="21"/>
</bean>
</beans>

As we can see in the application context file,we use the constructor parameter names to inject the dependencies.

PersonDemo.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonDemo {
public static void main(String[] args) {

   ApplicationContext bf= new ClassPathXmlApplicationContext(new String[]         
           {"personcontext.xml"});
   Person person= bf.getBean("person",Person.class);
   System.out.println(person);
}
}


OUTPUT

Person [name=Ram, age=21]

Tuesday, 3 March 2015

Bean creation in spring using factory method

Sometimes we will not need the spring container to instantiate the bean class.Instead we might need to use the Factory method(pattern) to instantiate the bean object.Lets says we have the below hierarchy of Classes
  • IProduct - Interface for  all the Product Classes
  • ProductOne,ProductTwo- Product concrete Implementation classes which implements the IProduct Interface
  • ProductFactory - Factory Class which creates the Object of type IProduct
IProduct.java

package test;

public interface IProduct {
public abstract void  doOperation();
}

ProductOne.java

package test;

public class ProductOne implements IProduct{

public ProductOne(String name) {
super();
this.name = name;
}

String name;

public String getName() {
return name;
}

@Override
public void doOperation() {
System.out.println("Done for Product:"+name);
}
}

ProductTwo.java

package test;

public class ProductTwo implements IProduct{
public ProductTwo(String name) {
super();
this.name = name;
}

String name;

public String getName() {
return name;
}

@Override
public void doOperation() {
System.out.println("Done for Product:"+name);
}
}


ProductFactory.java

package test;

public class ProductFactory {
public static IProduct getProduct(int productId)
{
IProduct product=null;
if(productId==1)
{
product=new ProductOne("ProductOne");
}
else if(productId==2)
{
product=new ProductTwo("ProductTwo");
}
return product;
}

}

we should use the class attribute to specify the name of the factory class and the factory-method attribute to specify the static factory method which will instantiate the bean.We can pass the value to this factory method by using the constructor-arg tag as shown below.

productcontext.xml

<?xml version="1.0" encoding="UTF-8"?&gt;
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="productbean1" class="test.ProductFactory" factory-method="getProduct">
<constructor-arg  value="1"/>
</bean>
<bean id="productbean2" class="test.ProductFactory" factory-method="getProduct">
<constructor-arg  value="2"/>
</bean>
</beans>


ProductDemo.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ProductDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext bf= new ClassPathXmlApplicationContext(new String[]            
               {"productcontext.xml"});
   IProduct product1= bf.getBean("productbean1",IProduct.class);
   product1.doOperation();
   IProduct product2=bf.getBean("productbean2",IProduct.class);
   product2.doOperation();
}
}

When we ask for the bean productbean1 and productbean2,the spring container will delegate the call to the factory class "ProductFactory" to instantiate the bean object

OUTPUT

Done for Product:ProductOne
Done for Product:ProductTwo

Sunday, 8 February 2015

To implement Binary Search algorithm in Java

Below program sample will show how to search for a particular element in the array using binary search.Make sure the array is sorted before we use the binary search.Binary search algorithm is very fast when compared to linear search(where each element in the array is checked).
Binary Search algorithm is pretty simple:
  • First it will check the middle element of the array.
  • If it is smaller than the search element,then the first part of the array is considered for the further search(leaving behind the second part),
  • Else the second part of the array is considered for the further search.
  • The above logic is continued until we find the search element or the start index of the filtered array is not greater than end index(where the element is not found)
public class BinarySearchSample {                                                                                                      

public static void main(String[] args) {

int [] arry= new int[]{3,5,9,13,25,40,55,90,121,150};
        int low=0;
        if(args.length==0)
        {
        System.out.println("Please pass the element to search in the array");
        }
        int src=Integer.parseInt(args[0]);//element to Search for
        int mid=0;
        int high=arry.length-1;
        boolean isFound=false;
        while(low<=high)
        {
        mid=(low+high)/2;
        System.out.println("low:"+low+" mid:"+mid+" high:"+high);
        if(src<arry[mid])
        {
        high=mid-1;
        }
        else if(src > arry[mid])
        {
        low=mid+1;
        }
        else
        {
        isFound=true;
        break;
        }        
        }
if(isFound)
{
System.out.println("Found "+src+" at index:"+mid);
}
else
{
System.out.println(src+" not found");
}
}
}

Output:

When you run the above program by passing the argument as 150(element to search for),we will get the below output

low:0 mid:4 high:9                                                                                                                                  
low:5 mid:7 high:9
low:8 mid:8 high:9
low:9 mid:9 high:9
Found 150 at index:9

If we analyse the above output,binary search took only 4 iterations to find the last element in the array,whereas in linear search it will take 10 iterations to find the same element in the above array.

Saturday, 6 September 2014

Collections algorithm - rotate,frequency,min,max and disjoint with sample program

In the post "Collections algorithm" we have seen about the algorithms reverse,shuffle,swap,fill and replace available in Collections class. Here we will see about the below remaining algorithm available in java.util.Collections.
  • rotate - This static method will rotate the specified list forward or backward by a specified distance.To move the list forward provide the distance as positive integer and to move backward provide the distance as negative integer.
  • frequency- This static method will return the count of the specified element exist in the specified list.
  • min- This static method will return the minimum element of the specified list according to the natural ordering of the element in the list.
  • max  - This static method will return the maximum element of the specified list according to the natural ordering of the element in the list.
  • disjoint - This static method will return true, if the two specified collection has no common elements between them.It will return false, if there is any common element between them.
Below sample program will illustrate how these methods can be used.

import java.util.ArrayList;                                                                                                                           
import java.util.Collections;
import java.util.List;

public class CollectionsSample {

public static void main(String[] args) {
CollectionsSample collectionsSample= new CollectionsSample();
collectionsSample.rotate();
collectionsSample.frequency();
collectionsSample.min();
collectionsSample.max();
collectionsSample.disjoint();
}

private void rotate() {
List<String> list=initializeList();
System.out.println("Values in the list before rotating:"+list);
Collections.rotate(list,1);
System.out.println("Values in the list after rotating forward by 1 position:"+list+"\n");
list=initializeList();
System.out.println("Values in the list before rotating:"+list);
Collections.rotate(list,-1);
System.out.println("Values in the list after roating backward by 1 position:"+list+"\n");
}
private void frequency() {
List<String> list=initializeList();
System.out.println("Values in the list :"+list);
int count =Collections.frequency(list, "HYUNDAI");
System.out.println("Number of Hyundai element in the list:"+count+"\n");
}
private void min() {
List<String> list=initializeList();
System.out.println("Values in the list:"+list);
String minElement=Collections.min(list);
System.out.println("Minimum element in the list is:"+minElement+"\n");
}

private void max() {
List<String> list=initializeList();
System.out.println("Values in the list:"+list);
String maxElement=Collections.max(list);
System.out.println("Maximum element in the list is:"+maxElement+"\n");
}
private void disjoint() {
List<String> list=initializeList();
List<String> secondList=new ArrayList<String>();
secondList.add("RENUALT");
secondList.add("AUDI");
System.out.println("Values in the first list :"+list);
System.out.println("Values in the second List :"+secondList);
boolean isDisjointList=Collections.disjoint(list, secondList);
if(isDisjointList)
{
 System.out.println("Above two list does not have any elements in common");
}
else
{
System.out.println("Above two list have some elements in common");  
}
}
private List<String> initializeList()
{
List<String> list= new ArrayList<String>();
list.add("HYUNDAI");
list.add("FORD");
list.add("HYUNDAI");
list.add("ZEN");
list.add("MARUTHI");
return list;
}
}

OUTPUT:

Values in the list before rotating:[HYUNDAI, FORD, HYUNDAI, ZEN, MARUTHI]
Values in the list after rotating forward by 1 position:[MARUTHI, HYUNDAI, FORD, HYUNDAI, ZEN]

Values in the list before rotating:[HYUNDAI, FORD, HYUNDAI, ZEN, MARUTHI]
Values in the list after roating backward by 1 position:[FORD, HYUNDAI, ZEN, MARUTHI, HYUNDAI]

Values in the list :[HYUNDAI, FORD, HYUNDAI, ZEN, MARUTHI]
Number of Hyundai element in the list:2

Values in the list:[HYUNDAI, FORD, HYUNDAI, ZEN, MARUTHI]
Minimum element in the list is:FORD

Values in the list:[HYUNDAI, FORD, HYUNDAI, ZEN, MARUTHI]
Maximum element in the list is:ZEN

Values in the first list :[HYUNDAI, FORD, HYUNDAI, ZEN, MARUTHI]
Values in the second List :[RENUALT, AUDI]
Above two list does not have any elements in common

Friday, 5 September 2014

Collections algorithm - reverse,shuffle,swap,fill and replace with sample program

There are many algorithm available in java.util.Collections class which provides many static util methods.
All these method take one of the argument as the list or the collection where the algorithm need to be applied. Some of them are:
  • reverse    - This static method will reverse the order of the specified list.
  • swap         - This static method will swap the elements at the specified positions of the  list.
  • shuffle      - This static method will reorders all the elements in the list randomly.
  • fill             - This static method will fill/replace all the elements in the list with a specified value.
  • replaceAll- This static method will replace all the occurrence of one specified value in the list with                           another value
Below sample program will illustrate how these methods can be used.

import java.util.ArrayList;                                                                                                                          
import java.util.Collections;
import java.util.List;

public class CollectionsSample {

public static void main(String[] args) {
CollectionsSample collectionsSample= new CollectionsSample();
collectionsSample.reverse();
collectionsSample.swap();
collectionsSample.shuffle();
collectionsSample.fill();
collectionsSample.replace();
}

private void reverse() {
List<String> list=initializeList();
System.out.println("Values in List before reverse:"+list);
Collections.reverse(list);
System.out.println("Values in List after reverse:"+list);
System.out.println();
}
private void swap() {
List<String> list=initializeList();
System.out.println("Values in List before swap:"+list);
Collections.swap(list,1,3);
System.out.println("Values in List after swap:"+list);
System.out.println();
}
private void shuffle() {
List<String> list=initializeList();
System.out.println("Values in List before shuffle:"+list);
Collections.shuffle(list);
System.out.println("Values in List after shuffle:"+list);
System.out.println();
}

private void fill() {
List<String> list=initializeList();
System.out.println("Values in List before fill:"+list);
Collections.fill(list,"NA");
System.out.println("Values in List after fill:"+list);
System.out.println();
}
private void replace() {
List<String> list=initializeList();
System.out.println("Values in List before replace:"+list);
Collections.replaceAll(list,"Tennis","TableTennis");
System.out.println("Values in List after replace:"+list);
System.out.println();
}
private List<String> initializeList()
{
List<String> list= new ArrayList<String>();
list.add("Cricket");
list.add("Footbal");
list.add("Tennis");
list.add("Baseball");
return list;
}
}

Output:

Values in List before reverse:[Cricket, Footbal, Tennis, Baseball]
Values in List after reverse:[Baseball, Tennis, Footbal, Cricket]

Values in List before swap:[Cricket, Footbal, Tennis, Baseball]
Values in List after swap:[Cricket, Baseball, Tennis, Footbal]

Values in List before shuffle:[Cricket, Footbal, Tennis, Baseball]
Values in List after shuffle:[Tennis, Footbal, Cricket, Baseball]

Values in List before fill:[Cricket, Footbal, Tennis, Baseball]
Values in List after fill:[NA, NA, NA, NA]

Values in List before replace:[Cricket, Footbal, Tennis, Baseball]
Values in List after replace:[Cricket, Footbal, TableTennis, Baseball]

Thursday, 4 September 2014

To secure and protect the sensitive information in serializable object

By using serialization we can save the  object state to the stream and we can  construct the saved object back from the stream when needed.Sometime we need to secure some attributes in our object to not to  get serialized i.e not to save its value.Consider the below code example where we are writing the StudentVo object to the file and reading back from it.

StudentVO.Java

import java.io.Serializable;                                                                                                                    

public class StudentVO implements Serializable {

private String loginId;

private  String password;

private String fullName;

private int age;

public StudentVO(String loginId, String password, String fullName,
int age) {
super();
this.loginId = loginId;
this.password = password;
this.fullName = fullName;
this.age = age;
}

@Override
public String toString() {
return "StudentVO [loginId=" + loginId + ", password=" + password
+ ", fullName=" + fullName + ", age=" + age + "]";
}
}

SerializerSample.java

import java.io.FileInputStream;                                                                                                              
import java.io.FileOutputStream;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializerSample {

private final static String  FILE_NAME="D:/objfile";

public static void main(String[] args) {
      StudentVO studentVO = new StudentVO("V01", "pwd", "John Peter", 20);
      SerializerSample serializerSample= new SerializerSample();
      serializerSample.serialize(studentVO);
      studentVO=serializerSample.deSerialize();
      System.out.println("Object deserialized from file is:"+studentVO.toString());
}

private void serialize(StudentVO  studentVO)
{
try {
    FileOutputStream fileOutputStream= new FileOutputStream(FILE_NAME);
      ObjectOutputStream objectOutputStream=new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(studentVO);
   fileOutputStream.close();
   objectOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}

private StudentVO deSerialize()
{
StudentVO studentVO=null;
try
{
FileInputStream fileInputStream= new FileInputStream(FILE_NAME);
ObjectInputStream objectInputStream= new ObjectInputStream(fileInputStream);
studentVO=(StudentVO) objectInputStream.readObject();
   fileInputStream.close();
   objectInputStream.close();
}catch (Exception e) {
e.printStackTrace();
}
return studentVO;
}
}

As we can see in the Class SerializerSample,first we will  write the object state to the file(in method serialize()) and then construct the object back from the file(in method deSerialize()).
When we run the program,we will get the below output:

Object deserialized from file is:StudentVO [loginId=V01, password=pwd, fullName=John Peter, age=20]

Since the password is an sensitive attribute,we should not save its value when serilaized into the file.
There are three ways to secure a serializable object
  1. Declaring the sensitive field as transient
  2. Declaring the field serialPersistentFields
  3. Defining writeObject and readObject methods
1)Declaring the sensitive field as transient

values for the attributes which are declared as transient will not be saved when the object is serialized.So declare the field password as transient in StudentVO as shown below,so that its state will not be saved.

private transient String password;                                                                                                              

2)Declaring the field serialPersistentFields

we can define the serializable fields that need to be saved using the attribute serialPersistentFields in the serializable class.This field should be initialized with an array of ObjectStreamField as shown below.

import java.io.ObjectStreamField;                                                                                                            
import java.io.Serializable;

public class StudentVO implements Serializable {
private String loginId;
private  String password;
private String fullName;
private int age;

private static final ObjectStreamField[] serialPersistentFields
 = {new ObjectStreamField("loginId", String.class),
      new ObjectStreamField("fullName", String.class),
      new ObjectStreamField("age",Integer.TYPE)};

public StudentVO(String loginId, String password, String fullName,
int age) {
super();
this.loginId = loginId;
this.password = password;
this.fullName = fullName;
this.age = age;
}

@Override
public String toString() {
return "StudentVO [loginId=" + loginId + ", password=" + password
+ ", fullName=" + fullName + ", age=" + age + "]";
}
}


We have defined only the fields loginid,fullName and age in the serialPersistentFields so that only this fields will be saved to the file on serialization and not the password field.

3)Defining writeObject and readObject methods in the Serializable Class

We can define the methods writeObject and readObject in the serializable class to control what information to be saved and to be retrieved back from the stream.

import java.io.IOException;                                                                                                                      
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class StudentVO implements Serializable {
private String loginId;
private  String password;
private String fullName;
private int age;
 public StudentVO(String loginId, String password, String fullName,
int age) {
super();
this.loginId = loginId;
this.password = password;
this.fullName = fullName;
this.age = age;
}

 private void readObject(ObjectInputStream ois) throws IOException,                                          
 ClassNotFoundException {
loginId=(String) ois.readObject();
fullName=(String) ois.readObject();
age=ois.readInt();
}
 private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.writeObject(loginId);
    oos.writeObject(fullName);
    oos.writeInt(age);
 }

@Override
public String toString() {
return "StudentVO [loginId=" + loginId + ", password=" + password
+ ", fullName=" + fullName + ", age=" + age + "]";
}
}

When the StudentVo object is serialized using writeObject method of the objectOutputStream,it will delegate the call to the method writeObject in serializable class StudentVO class.Thus only the fields loginId,fullName and age will be saved and not the password field.

OUTPUT:

When we run the SerializerSample class by using any of the above 3 versions of the StudentVO,we will get the below output

Object deserialized from file is:StudentVO [loginId=V01, password=null, fullName=John Peter, age=20]

As we can see in the output, the password field value was not saved during serialization.