Honnestly, I’m not surprised. We’ve got an aspect that hits every single method call on every object, AND it needs to do reflection and interpret through an EL.

But, really; it’s friggin slow. Prohibitively slow. Painfully slow.

The test

There’s nothing magic in all this code. It’s only an interface where the contracts are defined, a bogus implementation and a test class containing two test methods. The first method uses nothing at all (straight objects with no contracts), and the second method uses the full burito.

First thing was the interface

public interface IPersonManager {
   @Precondition( condition = "arg1 > 0" )
   @Postcondition(condition="not empty return and return.id > 0")
   public Person getPerson(int id);

   @Postcondition(condition="not empty return")
   public List<Person> getAll();

   @Precondition(bindArgs="arg1=person", condition = "not empty person and person.id < 1")
   @Postcondition(condition="not empty return and return.id > 0")
   public Person insert(Person person);

   @Precondition(bindArgs="arg1=person", condition = "not empty person and person.id > 0")
   @Postcondition(condition="not empty return and return.id > 0")
   public Person update(Person person);

   @Precondition(bindArgs="arg1=person", condition = "not empty person and person.id > 0")
   public void delete(Person person);
}

And a simple bogus implementation

public class PersonManagerImpl implements IPersonManager {
   public void delete(Person person) {
   }

   public List<Person> getAll() {
      List<Person> list = new ArrayList<Person>();
      list.add(new Person());
      return list;
   }

   public Person getPerson(int id) {
      Person p = new Person();
      p.setId(id);
      p.setFirstName("Mike");
      p.setLastName("McLean");
      return p;
   }

   public Person insert(Person person) {
      Person p = new Person();
      p.setId(3);
      p.setFirstName("Mike");
      p.setLastName("McLean");
      return p;
   }

   public Person update(Person person) {
      return person;
   }
}

The spring configuration


 


	
		
			
     	
  	 

	 

	

And finally the test class:

@Test
	public void testWithNoContracts() throws Exception {
		IPersonManager manager = new PersonManagerImpl();

		long start = System.currentTimeMillis();
		loopAFewTimes(manager);
		long end = System.currentTimeMillis();

		System.out.println("No spring, no contracts: " + ((end - start) / 1000) + " seconds and " + (end - start)  + " millis.");
	}

	@Test
	public void testWithContracts() throws Exception {
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
		IPersonManager manager = (IPersonManager)  context.getBean("personManager");

		long start = System.currentTimeMillis();
		loopAFewTimes(manager);
		long end = System.currentTimeMillis();

		System.out.println("Full enchilada: " + ((end - start) / 1000) + " seconds and " + (end - start)  + " millis.");
	}

	public void loopAFewTimes(IPersonManager manager) {
		for (int x = 0; x < 10000; x++) {
			manager.getPerson(1);
			manager.getAll();

			Person personInsert = new Person();
			personInsert.setId(0);

			manager.insert(personInsert);

			Person personUpdate = new Person();
			personUpdate.setId(2);
			manager.update(personUpdate);

			manager.delete(personUpdate);
		}
	}

The results

No spring, no contracts: 0 seconds or 14 millis.
Full enchilada: 24 seconds or 24792 millis.

Now, I understand that this is not scientific, bordering on stupid and unprofessional, but still. Across 10000 loops ....! Nuff said.

I'd seriously have to re-consider using this in anything that has any need for performance. I might consider it for a low-traffic data entry site, but nothing much more. I haven't tried other implementations, so this might not be fair towards the whole DBC community.