Java POJO and Java Bean Example
1. Introduction
POJO stands for a Plain Old Java Object. It’s a term coined by Martin Fowler, Rebecca Parsons, and Josh MacKenzie while preparing for a conference in September 2000. POJO is an ordinary Java object which doesn’t tie to any framework or external reference. It has no naming rule for its methods nor data members.
Java Bean is a Java object which meets Java Bean Conventions:
- Properties must set as
private
and expose via getters/setter. - The getter and setter must name as
getX
(isX
forboolean
) andsetX
convention. - Must have a public default no-argument constructor
- Must implement
java.io.serializable
interface
In this example, I will demonstrate the following items in a Maven project.
- Define a POJO class
- Define a Java Bean class
- Create a POJO object via Reflection
- Create a Java Bean object via Reflection
2. Technologies Used
The example code in this article was built and run using:
- Java 11
- Maven 3.3.9
- Eclipse Oxygen
- Junit 4.12
- Apache Commons BeanUtils 1.9.3
3. Maven Project
3.1 Dependencies
I will include Junit
and commons-beanutils
in the pom.xml
.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>java-pojo-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>11</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils --> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency> </dependencies> </project>
3.2 POJO
I will create a POJODemo
class which represents a POJO and includes:
- six fields naming from
field1
tofield6
with various access modifiers toString
to return aString
value of the object- constructor to build an object with the
field1
value
POJODemo.java
package jcg.zheng.demo.data; import java.util.ArrayList; import java.util.List; public class POJODemo { private int field1; public Long field2; Integer field3; protected String field4; public List<String> field5 = new ArrayList<>(); public boolean field6; public POJODemo(final int field1) { super(); this.field1 = field1; } @Override public String toString() { return "POJODemo [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4 + ", field5=" + field5 + ", field6=" + field6 + "]"; } public Integer getField3() { return field3; } public void setField3(Integer field3) { this.field3 = field3; } }
3.3 Java Bean
I will create a JavaBeanDemo
class which has the same six fields as the POJODemo
class but satisfies the Java Bean conventions:
- has a public default constructor
- all properties have a
private
access modifier - all properties have getX (isX) and setX
- implements
Serializable
interface
JavaBeanDemo.java
package jcg.zheng.demo.data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class JavaBeanDemo implements Serializable { private static final long serialVersionUID = 1L; private int field1; private Long field2; private Integer field3; private String field4; private List<String> field5 = new ArrayList<>(); private boolean field6; public JavaBeanDemo() { super(); } public int getField1() { return field1; } public Long getField2() { return field2; } public Integer getField3() { return field3; } public String getField4() { return field4; } public List<String> getField5() { return field5; } public boolean isField6() { return field6; } public void setField1(int field1) { this.field1 = field1; } public void setField2(Long field2) { this.field2 = field2; } public void setField3(Integer field3) { this.field3 = field3; } public void setField4(String field4) { this.field4 = field4; } public void setField5(List<String> field5) { this.field5 = field5; } public void setField6(boolean field6) { this.field6 = field6; } @Override public String toString() { return "JavaBeanDemo [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + ", field4=" + field4 + ", field5=" + field5 + ", field6=" + field6 + "]"; } }
You can also check our Java Bean example for further knowledge.
3.4 PlayingCard
I will create a PlayingCard
class which is a POJO with:
- two
String
data members –faceValue
andsuit
- constructor to build an object with both
faceValue
andsuit
toString
method to return aString
value of the object
PlayingCard.java
package jcg.zheng.demo.data; public class PlayingCard { private String faceValue; private String suit; public PlayingCard(String suit, String faceValue) { super(); this.suit = suit; this.faceValue = faceValue; } @Override public String toString() { return "Card [suit=" + suit + ", faceValue=" + faceValue + "]"; } }
3.5 PlayingCard Bean
I will create a PlayingCardBean class which is a Java Bean and has the same data members as PlayingCard
.
PlayingCardBean.java
package jcg.zheng.demo.data; import java.io.Serializable; public class PlayingCardBean implements Serializable { private static final long serialVersionUID = 1L; private String faceValue; private String suit; public PlayingCardBean() { super(); } public PlayingCardBean(String suit, String faceValue) { super(); this.suit = suit; this.faceValue = faceValue; } public String getFaceValue() { return faceValue; } public String getSuit() { return suit; } public void setFaceValue(String faceValue) { this.faceValue = faceValue; } public void setSuit(String suit) { this.suit = suit; } @Override public String toString() { return "Card [suit=" + suit + ", faceValue=" + faceValue + "]"; } }
3.6 ReflectionService
In this step, I will create a ReflectionService
class which has three methods:
createInstanceViaDefaultConstructor
– creates an object via a given class’s default constructor.- createInstanceviaConstructorWithInt – creates an object via a given class’s constructor which takes one int argument.
- displayAllFields – displays all fields for a given class and set one of the fields –
field2
with 4.
ReflectionService.java
package jcg.zheng.demo; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; public class ReflectionService { public Object createInstanceviaDefaultConstructor(String objClassName) { Object object = null; try { object = Class.forName(objClassName).getDeclaredConstructor().newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { } return object; } public Object createInstanceViaConstructorWithInt(String objClassName, int intF) { Object object = null; try { object = Class.forName(objClassName).getDeclaredConstructor(int.class).newInstance(intF); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { } return object; } public void displayAllFields(Object obj) throws IllegalArgumentException, IllegalAccessException { Field[] allFields = obj.getClass().getDeclaredFields(); System.out.print("\nClass " + obj.getClass().getName() + " has declared fields: "); for (Field f : allFields) { System.out.printf("\n\t %s %s ", Modifier.toString(f.getModifiers()), f.getName()); if( "field2".equalsIgnoreCase(f.getName())) { f.setAccessible(true); f.set(obj, 4l); } } } }
4. JUnit Test
4.1 POJO Test
I will create POJODemoTest
which includes four tests:
create_via_reflection_with_default_constructor
–POJODemo
has no default constructor, so it cannot create an instance with the no-argument constructor- create_via_reflection_with_int_constructor – POJODemo has a constructor that takes an int argument, so it can be used to create an instance via reflection.
- displayAllFields – displays all the fields via reflection and set its field2 value to 4.
- test_BeanUtils_copyProperties – Apache BeanUtils.copyProperties only works for the properties which meet getter and setter format.
POJODemoTest.java
package jcg.zheng.demo.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.lang.reflect.InvocationTargetException; import org.apache.commons.beanutils.BeanUtils; import org.junit.Test; import jcg.zheng.demo.ReflectionService; public class POJODemoTest { private static final String POJO_DEMO = "jcg.zheng.demo.data.POJODemo"; private POJODemo testClass = new POJODemo(3); private Object objectFromReflection; private ReflectionService reflectionDao = new ReflectionService(); @Test public void create_via_reflection_with_default_constructor() { objectFromReflection = reflectionDao.createInstanceviaDefaultConstructor(POJO_DEMO); assertNull(objectFromReflection); } @Test public void create_via_reflection_with_int_constructor() { objectFromReflection = reflectionDao.createInstanceViaConstructorWithInt(POJO_DEMO, 4); assertNotNull(objectFromReflection); } @Test public void displayAllFields() throws IllegalArgumentException, IllegalAccessException { reflectionDao.displayAllFields(testClass); assertEquals(4, testClass.field2.intValue()); } @Test public void test_BeanUtils_copyProperties() throws IllegalAccessException, InvocationTargetException { testClass.field2 = 100l; testClass.field3 = 123; testClass.field4 = "Mary"; testClass.field6 = true; POJODemo dest = new POJODemo(4); BeanUtils.copyProperties(dest, testClass); System.out.println(dest); // Did not copy any properties at all assertTrue(dest.toString().contains("field1=4")); assertTrue(dest.toString().contains("field2=null")); assertTrue(dest.toString().contains("field3=123")); assertTrue(dest.toString().contains("field4=null")); assertTrue(dest.toString().contains("field5=[]")); assertTrue(dest.toString().contains("field6=false")); assertEquals(dest.getField3().intValue(), testClass.getField3().intValue()); } }
Junit output
Running jcg.zheng.demo.data.POJODemoTest POJODemo [field1=4, field2=null, field3=123, field4=null, field5=[], field6=false] Class jcg.zheng.demo.data.POJODemo has declared fields: private field1 public field2 field3 protected field4 public field5 public field6 Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.02 sec Results : Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
4.2 Java Bean Test
I will create JavaBeanTest
to test the following:
create_via_reflection_with_default_constructor
–JavaBeanDemo
has a default constructor, so it can create an instance with the no-argument constructordisplayAllFields
– displays all the fields via reflection and set itsfield2
value to 4.test_BeanUtils_copyProperties
– ApacheBeanUtils.copyProperties
works for the Java Bean properties
JavaBeanDemoTest.java
package jcg.zheng.demo.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.lang.reflect.InvocationTargetException; import org.apache.commons.beanutils.BeanUtils; import org.junit.Test; import jcg.zheng.demo.ReflectionService; public class JavaBeanDemoTest { private static final String BEAN_DEMO = "jcg.zheng.demo.data.JavaBeanDemo"; private JavaBeanDemo testClass = new JavaBeanDemo(); private Object objectFromReflection; private ReflectionService reflectionDao = new ReflectionService(); @Test public void create_via_reflection_default_constructor() { objectFromReflection = reflectionDao.createInstanceviaDefaultConstructor(BEAN_DEMO); assertNotNull(objectFromReflection); } @Test public void getDeclaredFields() throws IllegalArgumentException, IllegalAccessException { reflectionDao.displayAllFields(testClass); assertEquals(4, testClass.getField2().intValue()); } @Test public void test_copyProperties() throws IllegalAccessException, InvocationTargetException { testClass.setField2(100l); testClass.setField3(123); testClass.setField4("Mary"); testClass.setField6(true); testClass.setField1(3); JavaBeanDemo dest = new JavaBeanDemo(); BeanUtils.copyProperties(dest, testClass); System.out.println(dest); assertEquals(3, dest.getField1()); assertEquals(100, dest.getField2().intValue()); assertEquals(123, dest.getField3().intValue()); assertEquals("Mary", dest.getField4()); assertTrue(dest.isField6()); } }
Junit Output
Running jcg.zheng.demo.data.JavaBeanDemoTest Class jcg.zheng.demo.data.JavaBeanDemo has declared fields: private static final serialVersionUID private field1 private field2 private field3 private field4 private field5 private field6 JavaBeanDemo [field1=3, field2=100, field3=123, field4=Mary, field5=[], field6=true] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.257 sec
4.3 Bean Disadvantage Test
I will create a BeanDisadvantageTest
class which demonstrates that the object’s state is updated by the bean’s setter when it should be the same during its life cycle. For a PlayingCard object, its face value and suit should not be changed. But setters enable other processes to update them, which sometimes causes confusion or problem. This is one of drawback about the Java Bean.
BeanDisadvantageTest.java
package jcg.zheng.demo.data; import static org.junit.Assert.*; import org.junit.Test; public class BeanDisadvantageTest { @Test public void javabean_state_changes_by_setter() { PlayingCard aceSpadePojo = new PlayingCard("Spade", "A"); assertEquals("Card [suit=Spade, faceValue=A]", aceSpadePojo.toString()); PlayingCardBean aceSpadeBean = new PlayingCardBean("Spade", "A"); aceSpadeBean.setSuit("Club"); aceSpadeBean.setFaceValue("1"); // OOPS. the variable aceSpadeBean now changed to Club 1 assertEquals("Card [suit=Club, faceValue=1]", aceSpadeBean.toString()); } }
Junit Output
Running jcg.zheng.demo.data.BeanDisadvantageTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.165 sec
5. Summary
As you saw in this example, Java Bean is a subset of POJO. They both can be created via Java reflection. Here are the major differences between them:
POJO | Java Bean | |
Description | A normal Java object which meets Java programming language specification | A subset of POJO which meets Java Beans specification |
Used By | Any application. e.g. Spring framework uses it widely. All Spring Beans are POJO | A builder tool which creates an instance via a toolbox. Apache commons BeanUtils |
Disadvantage | NA | Default constructor and public setter can change the object state when it should be immutable. |
6. Download the Source Code
You can download the full source code of this example here: Java POJO and Java Bean Example