Separation of Concerns: Refactoring of Evolving Project

Introduction

This article is in relationship to refactoring the SOAP/REST server presented in: Simple Spring-WS Application [with JPA and Jersey REST].

As the project has evolved some ugly coupling has reared its’ head.  In an expedient way the entity classes were annotated with JAXB annotations to make them available for serialization for our REST implementation.  Here the JAXB worked in conjunction with Jersey REST adapters to create JSON messages to serialize our objects. 

The Refactoring

There are many draw backs to taking this direct approach:

  • Muddying the definition of entity objects
  • Need to use GenericEntity to handle type erasure in the entity class which alters the class signature
  • From using GenericEntity and JAXB Annotations these libraries would have to be included in applications using the entity object even if these features were not used.
  • Complicates extensions to the entity
  • From a REST perspective it does not give us clean control over the information we choose to serialize.

 The Original com.persistent.entity.Company Class

@XmlRootElement(name = "company")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@Entity
@Table(name = "COMPANY")
@NamedQueries( { @NamedQuery(name = "Company.EagerFindByID", query = "SELECT c FROM Company c left join fetch c.employees where c.id =?1")
				}
			)
public class Company {
	private static final long serialVersionUID = -142950147106627846L;
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String name;
	@OneToMany(mappedBy = "company", fetch = FetchType.LAZY)
	private List<Person> employees = new ArrayList<Person>();

	/**
	 *
	 */
	public Company() {
	}

	@XmlElement
	public Long getId() {
		return id;
	}
	public void setId(final Long id) {
		this.id = id;
	}
	@XmlElement
	public String getName() {
		return name;
	}
	public void setName(final String name) {
		this.name = name;
	}

	public GenericEntity<List<Person>> getEmployees() {
		return new GenericEntity<List<Person>>(employees) {};
	}

The standard solution to this problem is the Transfer Object pattern.  Although we are changing the entity class annotations in an environment where it is being utilized by both REST and SOAP only the REST protion of the project is affected.  The SOAP functionality generates its own JAXB annotated transfer objects through the use XJC.

The following steps were required to implement the refactoring:

  1. Removed the JAXB annotations from the entity classes
  2. Create the transfer objects for each of the entity classes with JAXB annotations
  3. Added Dozer to facilitate the mapping from the entity classes to the transfer objects
  4. execute the mappings in the CompanyDirectoryRest class were the conversion is required.

 The com.persistent.entity.Company Class after the decoupling

@Entity
@Table(name = "COMPANY")
@NamedQueries( { @NamedQuery(name = "Company.EagerFindByID", query = "SELECT c FROM Company c left join fetch c.employees where c.id =?1") })
public class Company implements Serializable {
	private static final long serialVersionUID = -142950147106627846L;
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String name;
	@OneToMany(mappedBy = "company", fetch = FetchType.LAZY)
	private List<Person> employees = new ArrayList<Person>();

	/**
	 *
	 */
	public Company() {
	}

	public Long getId() {
		return id;
	}

	public void setId(final Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(final String name) {
		this.name = name;
	}

	public List<Person> getEmployees() {
		return employees;
	}

The com.persistent.dto.Company Class for Data Transfer

@XmlRootElement(name = "company")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public class Company implements Serializable {
	@XmlTransient
	private static final long serialVersionUID = -142950147106627846L;

	private Long id;
	private String name;
	private List<Person> employees = new ArrayList<Person>();
	/**
	 *
	 */
	public Company() {
	}

	public Company(com.persistent.entity.Company company) {
		this.name = company.getName();
		this.id = company.getId();
	}

	@XmlElement
	public Long getId() {
		return id;
	}
	public void setId(final Long id) {
		this.id = id;
	}
	@XmlElement
	public String getName() {
		return name;
	}
	public void setName(final String name) {
		this.name = name;
	}

	public GenericEntity<List<Person>> getEmployees() {
		return new GenericEntity<List<Person>>(employees) {};
	}

 

The JUnit test cases proved their worth as these changes were made to quickly establish their effectiveness.

The interfaces between components is maintained so that the JUnit tests do not need to change.  This refactoring mainly effects the maintainability and extensibility of the software.  This application will work with the SOAP Client described in the previous article: Simple SOAP Client using XMLBeans.

A Note on Dozer

Dozer does implicit-explicit mappings between classes.  It provides complex mapping between dis-similar classes.  We are utilizing it simply but it is an application that does provide flexibility that will provide value in the long run when there may be more interest in interesting mappings.  Even used simply it does provide an intuitive flow to the code which leads to maintainability as we show below.

By providing a simple mapping file, as in our case general-dozer-bean-mappings.xml, we describe the desired mapping.  We rely on the implicit mapping fascilities of the tool:

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net

http://dozer.sourceforge.net/schema/beanmapping.xsd">

  <mapping>
    <class-a>com.persistent.entity.Company</class-a>
    <class-b>com.persistent.dto.Company</class-b>
    <field-exclude>
      <a>employees</a>
      <b>employees</b>
    </field-exclude>
  </mapping>
  <mapping>
    <class-a>com.persistent.entity.Person</class-a>
    <class-b>com.persistent.dto.Person</class-b>
  </mapping>
</mappings>

Now performing the mapping is trivial in this snippet, taken from CompanyDirectoryRest.java,  we map the entity object into a JAXB annotated transfer object for serialization.

 

@Autowired
Mapper servermapper;

@GET
@Path("/persons")
@Produces("application/json")
public List<com.persistent.dto.Person> getPersons() {
	log.info("getPersons entered");
	List<Person> persons = companyDirectory.getPersons();
	List<com.persistent.dto.Person> personDTOs = new ArrayList<com.persistent.dto.Person>();

	for (Person person : persons) {
		personDTOs.add(getPersonDto(person));
	}

	return personDTOs;
}

private com.persistent.dto.Person getPersonDto(Person person) {
	com.persistent.dto.Person personDTO = servermapper.map(person, com.persistent.dto.Person.class);
	return personDTO;
}

Conclusion

We have decoupled the JAXB annotations from the entity objects and have utilized a data transfer object to provide the JAXB conversion.  This decoupling leads to greater easy of extention to our entities and places the JAXB services closer to the point of use rather than bleeding them into other parts of the application.

Build Instructions

The build instructions are the same as before.  Click here for the build instructions.

The Source Code

updated Source Code: October 29, 2009

About The Author

David Sells is a computer consultant in Toronto, Ontario who specializing in Java Enterprise Development. He has  provided innovative solutions for clients including: IBM, Goldman Sachs, Merrill Lynch and Deutsche Bank.

He also holds the following certifications:

  • Sun Certified Enterprise Architect for the Java Platform, Enterprise Edition 5 (2009)
  • Sun Certified Web Component Developer
  • Sun Certified Java Programmer.

Contact: david@persistentdesigns.com

 

2 comments to Separation of Concerns: Refactoring of Evolving Project

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>