Anda di halaman 1dari 23

Promoting Software Reuse via Generics & Reflection in Java

- A Practical Case -

Mohamed Ennahdi El Idrissi m.ennahdielidrissi@aui.ma

Introduction
Its not always obvious to simply understand a concept Facing a concrete situation helps to clearly and straightforwardly understand
What is the concept about ? Why is it used ?

We want to understand Reflection, with Generics


offer a higher level of abstraction makes java more flexible than ever

Prerequisites
You should be familiar with:
Java JDBC (PreparedStatement ) SQL Design Patterns (DAO )

Scenario
Lets consider two classes:
Person Car

A person owns many cars A car is owned by one and only one person

Scenario
Imagine we will implement the following scenario
Display a list of persons Select one person
Display person details

Among details, a list of cars Select a car


Display car details

Scenario
4- Detail Car 1- List Persons

3- List Cars

2- Detail Person

Person
private private private private private BigDecimal id; String firstName; String lastName; String email; List<Car> cars;

public Person(); public Person(ResultSet); public public public public public public public public public public BigDecimal getId(); void setId(BigDecimal); String getFirstName(); void setFirstName(String); String getLastName(); void setLastName(String); String getEmail(); void setEmail(String); List<Car> getCars(); void setCars(List<Car>);

Car
private String name; private BigDecimal model; private String plateNumber;
public Car(); public Car(ResultSet); public public public public public public String getName(); void setName(String); BigDecimal getModel(); void setModel(BigDecimal); String getPlateNumber(); void setPlateNumber (String);

public class Car { private String private BigDecimal private String


/* * Default Constructor. */

name; model; plateNumber;

public Car() { this.name = ; this.model = new BigDecimal(0); this.plateNumber = ;


} /* * Constructor with ResultSet. */ public Car(ResultSet rs) { this.name = rs.getString(NAME); this.model = rs.getBigDecimal(MODEL); this.plateNumber = rs.getString(EMAIL); } /* * Getters & Setters. */ }

public class Person { private BigDecimal id; private String firstName; private String lastName; private String email; private List<Cars> cars; /* * Default Constructor. */ public Person() { this.id = null; this.firstName = ; this.lastName = ; this.email = ; this.cars = null; } /* * Constructor with ResultSet. */ public Person(ResultSet rs) { this.id = rs.getBigDecimal(ID_PERSON); this.firstName = rs.getString(FIRST_NAME); this.lastName = rs.getString(LAST_NAME); this.email = rs.getString(EMAIL); this.cars = null; } /* * Getters & Setters */ }

public class CarDAO extends DAO<Car> { public List<Car> getByPerson(BigDecimal id) { StringBuilder sql = new StringBuilder(); sql.append( SELECT sql.append( FROM sql.append( WHERE * ); CAR ); ID_PERS = ?);

PreparedStatement ps = this.getConnection().prepareStatement(sql.toString()); ps.setBigDecimal(1, id); ResultSet rs = requeteSQL.executeQuery(); List<Car> cars = new ArrayList<Car>(); while (rs.next()) { cars.add(new Car(rs)); } return cars;

}
}

public class PersonDAO extends DAO<Person> { public Person getByID(BigDecimal id) { StringBuilder sql = new StringBuilder(); sql.append( sql.append( sql.append( sql.append( sql.append( SELECT FROM JOIN ON WHERE * ); PERSON CAR p.ID_PERS p.ID_PERS

p c = =

); ); c.ID_PERS ); ?);

PreparedStatement ps = this.getConnection().prepareStatement(sql.toString()); ps.setBigDecimal(1, id); ResultSet rs = requeteSQL.executeQuery(); Person person = null; if (rs.next()) { person = new Person(rs); CarDAO carDAO = DAOFactory.getCarDAO(); List<Car> cars = carDAO.getByPerson(person.getId()); person.setCars(cars); } return person; } }

public class PersonDAO extends DAO<Person> { public List<Person> getAll() { StringBuilder sql = new StringBuilder(); sql.append( sql.append( sql.append( sql.append( SELECT FROM JOIN ON * ); PERSON p ); CAR c ); p.ID_PERS = c.ID_PERS );

PreparedStatement ps = this.getConnection().prepareStatement(sql.toString()); ResultSet rs = requeteSQL.executeQuery(); List<Person> persons = new ArrayList<Person>(); while (rs.next()) { Person p = new Person(rs); CarDAO carDAO = DAOFactory.getCarDAO(); List<Car> cars = carDAO.getCarsByPerson(person.getId()); p.setCars(cars); persons.add(p); } return persons; }

Wrapping a List attribute


To take further advantage of the constructor ResultSet argument
List Wrapper class

Meanwhile, we may need further operations to perform on list


Sort Search

Every time a list needs to be handled


Create an exclusive class for it

PersonList
private List<Person> persons; public PersonList(); public PersonList(ResultSet);

public String getPersons(); public void setPersons(List<Person>);


public List<Person> search(String); public void sort();

CarList
private List<Car> cars; public CarList(); public CarList(ResultSet); public List<Car> getCars(); public void setCars(List<Car>); public List<Car> search(String); public void sort();

/* * Constructor with ResultSet. */ Public PersonList(ResultSet rs) { [] while (rs.next) { this.persons.add(new Person(rs)); } [] } /* * Constructor with ResultSet. */ Public CarList(ResultSet rs) { [] while (rs.next) { this.cars.add(new Car(rs)); } [] }

Class Person becomes:


Person
private private private private private BigDecimal id; String firstName; String lastName; String email; CarList cars;

public Person(); public Person(ResultSet rs); public public public public public public public public public public BigDecimal getId(); void setId(BigDecimal); String getFirstName(); void setFirstName(String); String getLastName(); void setLastName(String); String getEmail(); void setEmail(String); CarList getCars(); void setCars(CarList);

List<Person> persons = new ArrayList<Person>(); while (rs.next()) { persons.add(new Person(rs)); }

PersonList persons = new PersonList(rs);

List<Car> cars = new ArrayList<Car>(); while (rs.next()) { cars.add(new Car(rs)); }

CarList cars = new CarList(rs);

Promoting Software Reusability!


PersonList & CarList have several commonalities:
List<Person> attribute & List<Car>
Lets opt for Generics!!!

Constructor with ResultSet


Should call a super constructor, centralize the same operations

search(String) & sort() methods

How to write these once?


Abstract Super Class Generics Reflection

<<abstract>> EntityList<T>
private List<T> aList; Public EntityList(); Public EntityList(ResultSet);
public abstract List<T> search(String); public abstract void sort();

PersonList<Person>
public PersonList(); public PersonList(ResultSet);

CarList<Car>
public CarList(); public CarList(ResultSet);

public List<Person> search(String); public void sort();

public List<Car> search(String); public void sort();

/* * Constructor with ResultSet. */ public void PersonList(ResultSet rs) { super(rs); } /* * Constructor with ResultSet. */ public void CarList(ResultSet rs) { super(rs); }

What is the implementation of the super class constructor EntityList(ResultSet)?

Since the super class EntityList has a generic type <T>


The constructor should look something like:
/* * Constructor with ResultSet, superclass! */ Public EntityList(ResultSet rs) { this.aList = new ArrayList<T>(); while (rs.next) { this.aList.add(new T(rs)); } }

How to write this properly in java?

Finally: Reflection, with Generics


/* * Constructor with ResultSet. */ Public EntityList(ResultSet rs) { ParameterizedType superclass = (ParameterizedType) this.getClass().getGenericSuperclass(); Class<T> object = (Class<T>) superclass.getActualTypeArguments()[0]; Class<?>[] params = {ResultSet.class}; Constructor<?> ct = object.getDeclaredConstructor(params); Object[] argList = {rs};

this.aListe = new ArrayList<T>(); while (rs.next) { this.aList.add((T) ct.newInstance(argList)); }


}

Conclusion
Absolute code reusability Usage of abstraction as most as possible
flexibility

Design Pattern
Custom List Wrapper? Imposes a top/down structure
abstract classes/interfaces

Anda mungkin juga menyukai