Home > Reverse Engineering

Java Reverse Engineering



Reverse engineering is a processes to rebuild UML model from language implementation. In Java, some information can be retrieved easily by parsing Java source code or by decoding class binary file structure, such as:

  • Java type class/interface
  • Inheritance
  • Attributes

Others need a complex code semantic analysis, such as:

  • Getter/setter methods
  • Cardinality of association
  • Element type in a collection
  • Inverse association resolution
  • Qualified association

Precisely, it is necessary to analyze method implementation content to capture them. EclipseUML Personal/Professional/Studio Edition provides a very powerful reverse engineering engine to meet these requirements based on the byte-code analysis. Additionally, it provides following features:

  • Model attribute detection
  • Alive dependence detection between classes and packages
  • Customizable dependence definition

EclipseUML Personal/Professional/Studio Edition uses the reverse engineering engine in two ways:

  • UML model reverse engineering
  • Dependency detection

 

Getter/setter method recognition

 

UML Reverse engineering detects automatically the getter/setter method of an attribute. It takes into account the prefix and suffix preferences of JDT. The name without prefix and suffix will be used as model name, named as property.

Concrete methods

If methods have the implementations, the UML reverse engineering analyze the code to make sure that the getter method returns this attribute value and the setter changes this attribute value. 

For example, with the prefix setting of "f", in the following Java class that contains an attribute name = fCompany, the property name will be "company"


public class Employee
{
    private Company fCompany;
    public Company getCompany()
    {
         return fCompany;
    }
    public void setCompany(Company company)
    {
         fCompany = company;
    }
}
public class Company
{
    ...
}

After the reverse engineering process, we find UML role name = company, instead of fCompany.

public class Employee
{
    /**
     * @uml property=company associationEnd={multiplicity={(0 1)} ordering=ordered 
     * elementType=company.Company}
     */
    private Company fCompany;
    /**
     * @uml property=company
     */
    public Company getCompany()
    {
        return fCompany;
    }
 
    /**
     * @uml property=company
     */
    public void setCompany(Company company)
    {
        fCompany = company;
    }
}

Abstract methods

In case of the abstract method: class abstract method or interface method, there is no code to analyze. So the only solution is to analyze the method name and signature according to JDT definition. The setter method is ignored if a getter method is missing in the class/interface.


Cardinality detection

 

EclipseUML Reverse Engineering Engine is capable to detect two groups of associations:

  • Cardinality 0..1 or 1, which correspond to simple reference
  • Cardinality 0...*, which correspond to a container reference

To classify an attribute type to one of the two groups; the key issue is container detection. In Java, there are two categories of containers: java.util.Collection and java.util.Map. EclipseUML reverse engineering implements a mechanism to recognize not only the interface java.util.Collection and java.util.Map, but also their subtypes or implementation classes such as java.util.List, java.util.Vector, java.util.Hashtable.

Cardinality 0...1 or 1

For a simple reference, if the attribute is always initialised, the cardinality will be 1. Otherwise, it will be 0..1.

Examples of cardinality 0..1

Before Reverse Engineering

After Reverse Engineering

public class Employee extends Person

{

    private Company company;

    public Company()

    {

    }

}

public class Employee extends Person

{

    /**

     * @uml property=company associationEnd={multiplicity={(0 1)}

     * }

     */

    private Company company;

    public Company()

    {

    }

}

 


Example of cardinality 0..1

Before Reverse Engineering

After Reverse Engineering

public class Employee extends Person

{

    private Company company;

    public Company(Company company)

    {

        this.company = company;

    }

}

public class Employee extends Person

{

    /**

     * @uml property=company associationEnd={multiplicity={(1 1)}

     * }

     */

    private Company company;

    public Company(Company company)

    {

        this.company = company;

    }

}

Cardinality 0...*

A container has always the cardinality 0..*.

Example of collection

Before Reverse Engineering

After Reverse Engineering

public class Company

{

    private Collection employees = new ArrayList();

    …

}

public class Company

{

    /**

     * @uml property=employees associationEnd={multiplicity={(0 -1)}

     * inverse={company:model.Employee}

     * }

     */

    private Collection employees = new ArrayList();

    …

}

 


Collection element type detection

EclipseUML Reverse engineering engine captures the element type in a collection by analysing content accessing code. For example, the argument of collection method add() may indicate the element type:

public class Company

{

   private List employees = new ArrayList();

   public Company(List employees)

   {

      this.employees = employees;

   }

   public void addEmployee(Employee employee)

   {

      employees.add(employee);

   }

   public Collection getEmployees()

   {

      return employees;

   }

}

The idea is very simple. But the real use cases are mush more complex. The same method may have different implementations.

Using local variable

public void addEmployee(Employee employee)

{

   Collection localVariable = employees;

localVariable.add(employee);

}

Clall getter

public void addEmployee(Employee employee)

{

getEmployees().add(employee);

}

Using getter and local variable

public void addEmployee(Employee employee)

{

Collection localVariable = getEmployees();

LocalVariable.add(employee);

}

Of course, these codes can be used outside of the class Company.

According the accessing type of this attribute, we distinguee the analyze mechanism in two categories:

·       Getter category

·       Setter category

The first one allows the forward analyze, the analyzer can follow the execution order. The typical example is the iteration method (see below). It is much easy than Setter category, which needs backward analyze mechanism.

1. Getter category

Each accessing method may have a specific way to capture the element type. So we classify all relevant methods as following groups according to the model capture mechanism:

  • Add, Remove, Index and Test group
  • Get group
  • Iteration group

1.1 Add, Remove, Index and Test group

This group includes following methods:

Class

Method

java.util.Collection

boolean add(Object object)

java.util.Vector

void addElement(Object object)

java.util.Vector

void add(int index, Object object)

java.util.Vector

Object set(int index, Object object)

java.util.Vector

Object elementSet (Object object, int index)

java.util.Vector

void setElementAt (Object object, int index)

java.util.Vector

void insertElementAt (Object object, int index)

 

Class

Method

java.util.Collection

boolean remove(Object object)

java.util.Vector

boolean removeElement(Object object)

java.util.Vector

void removeElement (Object object)

 

Class

Method

java.util.List

int indexOf (Object object)

java.util.List

int lastIndexOf(Object object)

java.util.Vector

int lastIndexOf (Object object, int index)

java.util.Collection

boolean contains (Object object)

The capture mechanism of this group is simplest one comparing others. We just need identify the method call and capture argument type. For example:

public void removeEmployee(Employee employee)

{

   Collection localVariable = employees;

localVariable.remove(employee);

}

or

public int getEmployeeIndex(Employee employee)

{

return employees.indexOf(employee);

}

1.2 Get group

This group consists of following methods:

Class

Method

java.util.List

Object get(int index)

java.util.Vector

Object elementAt(int index)

java.util.Vector

Object firstElement()

java.util.Vector

Object lastElement()

This group is a little bit difficult than previous one since we need analyze the next statements to capture the element type in type casting or the operator instanceof. For example,

public Employee getEmployeeAt(int index)

{

return (Employee) employees.get(index);

}

or

public boolean hasEmployeeAt(int index)

{

Object element = employees.get(index);

return (element instanceof Employee);

}

1.3 Iteration group

This group consists of following methods

Class

Method

java.util.Collection

Iterator iterator ()

java.util.List

Iterator listIterator ()

java.util.List

Iterator listIterator (int index)

java.util.Vector

Enumeration elements ()

This group is more difficult than previous one again since it is necessary to analyze the following cast and instanceof statements only after element retrieve call such as next() or nextElement(). For example,

Iterator iterator = company.getEmployees().iterator();

while (iterator hasNext())

{

   Employee employee = (Employee) iterator.next();

}

or

for (Iterator iterator = company.getEmployees().iterator(); iterator hasNext();)

{

   Employee employee = (Employee) iterator.next();

}

All casting and operator instanceof must be ignored without calling next(). Otherwise, the result will be wrong:

Iterator iterator = company.getEmployees().iterator();

Address address = (Address) getAddress();

while (iterator hasNext())

{

   Employee employee = (Employee) iterator.next();

}


2. Setter category

When the code assigns a filled container to this attribute, for example,

List employees = new ArrayList();

employees.add(new Employee());

Company company = new Company (employees);

or

List employees = new ArrayList();

employees.add(new Employee());

company.setEmployees(employees);

it is necessary to perform the semantic analyze following inverse execution order. EclipseUML Personal/Professional/Studio edition implements this sophistic mechanism. It is used only when the first category calls are missing.

 


Inverse association resolution

 

EclipseUML Reverse engineering uses following rules to resolve inverse associations:

  1. If Class A has an association “b” of type B and Class B hasn’t any association of type A, there isn’t inverse association.
  2. If Class A has an association “b” of type B and Class B has only one inverse association “a” of type A, we set up the two associations as inverse associations.
  3. If Class A has an association “b” of type B and Class B has more than one association of type A (for example, “a1” and “a2”), we try to resolve this conflict by analysing the accessing of the two couple of attributes: “b” and “a1”, “b” and “a2”.
    1. If there is only one method that accesses one couple of attributes directly or via getter/setter, this couple of attributes will be considered as inverse associations.
    2. If there is more than one method that accesses both couples of attributes, we use collected statistic to resolve this conflict.

For example:

public class Project

{

   private HashMap teams = new HashMap ();

      public void addTeamMember(String name, Employee member) {

            Collection team = (Collection) teams.get(name);

            if (team == null) {

                  team = new ArrayList();

                  teams.put(name, team);

            }

            team.add(member);

            member.setProject(this);

      }

}

The attribute accesses are in bold. So the associations implemented by the attribute teams and project are inverse associations.


Qualified  association detection

EclipseUML Reverse engineering engine can recognize the java.util.Map and its implementation classes such as java.util.HashMap and java.util.Hashtable. It can capture not only the key and value type, but also the element type in the associated value if it is a collection.

In the following illustration, we use the Company and Project class as example:

public class Company

{

   private Hashtable projects = new Hashtable ();

   public Company(Hashtable projects)

   {

      this.projects = projects;

   }

   public Hashtable getProjects()

   {

      return projects;

   }

   public void setProjects (Hashtable projects)

   {

      this.projects = projects;

   }

}

According the accessing type of this attribute, we distinguee the analyze mechanism in two categories:

  1. Getter category
  2. Setter category

The first one allows the forward analyze, the analyzer can follow the execution order. The typical example is the iteration method (see below). It is much easy than Setter category, which needs backward analyze mechanism.


1. Getter category

Each accessing method may have a specific way to capture the element type. So we classify all relevant methods as following groups according to the model capture mechanism:

  • Put, Remove, Index and Test group
  • Get group
  • Iteration group

1.1 Put, Remove  and Test group

This group includes following methods:

Class

Method

Recognition

java.util.Map

Object put(Object key, Object value)

Key and value

 

Class

Method

Recognition

java.util.Map

Object remove(Object object)

Key

 

Class

Method

Recognition

java.util.Map

boolean containsKey (Object object)

Key

java.util.Map

boolean containsValue (Object object)

Value

java.util.Hashtable

boolean contains (Object object)

Value

The capture mechanism of this group is simplest one comparing others. We just need identify the method call and capture argument type. For example:

public void putProject(String name, Project project)

{

   projects.put(name, project);

}

1.2 Get group

This group consists of following methods:

Class

Method

Recognition

java.util.Map

Object get(Object object)

Key and value

This group is a little bit difficult than previous one since we need analyze the next statements to capture the element type in type casting or the operator instanceof. For example,

public Project getProjectAt(String name)

{

return (Project) projectsMap.get(name);

}

1.3 Iteration group

This group consists of following methods

Class

Method

Recognition

java.util.Map

Iterator values ()

Value

java.util.Map

java.util.Set keySet()

followed by iterator()

Key

java.util.Map

Collection values()

followed by iterator()

Value

java.util.Hashtable

Enumeration keys ()

Key

java.util.Hashtable

Enumeration elements ()

Value

This group is more difficult than previous one again since it is necessary to analyze the following cast and instance of statements only after element retrieve call such as next() or next element(). For example,

Iterator iterator = company.getProjects().values().iterator();

while (iterator hasNext())

{

   Project project = (Project) iterator.next();

}

or

for (Iterator iterator = company. getProjects().keySet().iterator(); iterator hasNext();)

{

   String name = (String) iterator.next();

}

All casting and operator instance of must be ignored without calling next(). Otherwise, the result will be wrong:

Iterator iterator = company.getProjects().values().iterator();

Address address = (Address) getAddress();

while (iterator hasNext())

{

   Project project = (Project) iterator.next();

}


If the value is a collection, the element type mechanism will be used for deep analyze. Here is an example of the association teams between Employee and Project:

public class Project

{

   private HashMap teams = new HashMap ();

      public void addTeamMember(String name, Employee member) {

            Collection team = (Collection) teams.get(name);

            if (team == null) {

                  team = new ArrayList();

                  teams.put(name, team);

            }

            team.add(member);

            member.setProject(this);

      }

}

.