Introduction
Whenever there is an application to write, breaking it up to small pieces is a great idea. The smallest piece of any application would probably be a data object, or a simple Bean in Java. Java Beans are simple Java classes that have a distinctive look and behavior. Their simplest purpose is to contain data and they accomplish this by having properties. Each property is actually a data-member containing/referencing the actual data and a couple of methods, a getter method and a setter method. Thus, the simplest data-bean describing a person could be expressed as such:
public interface Person {
public String getFirstName();
public void setFirstName(String name);
public String getLastName();
public void setLastName(String name);
public int getAge();
public void setAge(int age);
}
Your first response could probably be, "where are the data-members?", or "why did you use an interface and not a class?" and you would be perfectly right in asking either one of those two important questions. The whole idea of breaking things down to small pieces is to create an API that need not be changed after it is agreed upon by all parties involved in the design and development of the code. Only then, should we generate code to support and use such APIs. However, during that first stage when APIs are developed, sometimes you need to add a property, change a property or maybe introduce a whole new Bean into the system. Testing your APIs is impossible if your Beans don't actually support their properties, so you have to actually implement some sort of a basic bean, or the Data-Bean as I call it.
In this article, I will make use of Java's Reflection to handle the automation of Data-Beans without writing more code than the previously mentioned interface or more like it.
Background
The code in this article uses the Arguments
class I have described in an earlier article titled: "Java Generic Code - Reflection, the Easy Way", and although the Arguments
class is included in the supplied source, I would advise you to read my article about Reflection just so that my DataBeanProxy
class will be easier to understand.
How the Code is Organized
Simply run the dev.easyref.tester.DemoApplication
class or double click on the JAR file supplied. The class structure is as follows:
Package |
Source File |
Purpose |
dev.easyref.tester |
DemoApplication |
The demo's main class. |
|
|
|
dev.easyref.data |
Person |
A simple data bean interface describing a Person 's properties. |
|
Employee |
An extension to the Person interface adding the Salary property. |
|
User |
An extension to the Employee interface adding the Pass word property. |
|
|
|
dev.easyref.util |
Arguments |
A utility class used to perform all the Reflection work. |
|
DataBean |
An interface describing basic methods a Data-Bean will need. |
|
DataBeanProxy |
An extension of the Arguments class that automatically provides code to support Data-Bean properties. |
How Things Work
Let's examine the main method of DemoApplication
:
01 public static void main(String[] args) {
02 ArrayList list = new ArrayList();
03
04 addUser(list, "WOOGA", 1500.0f, 25, "Ruth", "Barak");
05 addUser(list, "TESTER", 2000.0f, 40, "Odded", "Barak");
06 addUser(list, "BOOGA", 3000.0f, 35, "Doron", "Barak");
07
08 Collections.sort(list, new Comparator() {
09 public int compare(Object o1, Object o2) {
10 String s1 = ((User)o1).getFirstName();
11 String s2 = ((User)o2).getFirstName();
12 return s1.compareTo(s2);
13 }
14 });
15
16 System.out.println(list);
17 }
We can see that the interesting part is between lines 4 to 6, where three User
instances are created. Looking at the addUser(...)
method clears up things a little:
01 public static void addUser(Collection list, String psswd,
float salary, int age, String firstName, String lastName) {
02
03 User user = (User)DataBeanProxy.newDataBean(User.class);
04
05 user.setAge(age);
06 user.setSalary(salary);
07 user.setPassword(psswd);
08 user.setLastName(lastName);
09 user.setFirstName(firstName);
10
11 list.add(user);
12 }
The important bit here is line 3 where the DataBeanProxy
class is used as a Factory to create a User
instance. The newly created instance does implement the User
interface but to find out how, and where the data-properties are kept, you'll have to peek under the hood of the DataBeanProxy
class.
In Conclusion
Hopefully this article helps in realizing the power of Reflection and also how Reflection -- although arguably breaks OOP methodologies -- can be useful as an API building tool.