充血モデルの想定実現(2010/07/30更新)


2年前、貧血モデルと充血モデルの議論は熱烈だったが、具体的な実装では議論が多かった.肝心なのはJavaが動的言語ほど容易に実現できないためであり、分野モデルに関連するデータベースへのアクセス方法を動的に追加できれば、どのような状況になるのか.
最近バイトコードの操作に興味があり、領域モデルをコンパイルする際に、関連するバイトコードを動的に追加し、領域モデルを豊富にするとともにhibernateのサポートが必要となり、すべての@Entityの領域モデルを取得し、HibernateTemplate Fieldを追加し、aspectjを借りて領域モデルをインスタンス化する際にhibernateTemplateを注入したいと考えています.(Spring Rooはこのように実現されています...)(他のオブジェクトを注入する必要がある場合は、同じように)

// ASM      :
@Transient
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate() {
	return hibernateTemplate;
}
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
	this.hibernateTemplate = hibernateTemplate;
}

各entityにpersistenceメソッドを追加すると、DAO層を省くことができます.ビジネス層はトランザクション、セキュリティなどのロジックを管理し、以下のコードのバイトコードを追加し、添付ファイルのコードを具体的に参照します.実際にはantコマンドを追加します.バイトコードを一括追加します.

public void create() throws DataAccessException {
	hibernateTemplate.save(this);
}

public void createOrUpdate() throws DataAccessException {
	hibernateTemplate.saveOrUpdate(this);
}

public void delete() throws DataAccessException {
	hibernateTemplate.delete(this);
}

public Message find() throws DataAccessException {
	return hibernateTemplate.get(this.getClass(), id);
}

public void update() throws DataAccessException {
	hibernateTemplate.update(this);
}

public List<Message> findByProperty(String propertyName, Object value) throws DataAccessException {
	Assert.hasText(propertyName);
	Assert.notNull(value);

	StringBuilder buf = new StringBuilder();
	buf.append("FROM ").append(this.getClass().getSimpleName()).append(" WHERE ").append(propertyName).append(" = :condition");
	List<Message> entities = this.getHibernateTemplate().findByNamedParam(buf.toString(), "condition", value);
	return entities;
}

public List<Message> findAll() throws DataAccessException {
	return (List<Message>) hibernateTemplate.loadAll(this.getClass());
}

テストの例は次のとおりです.

final HibernateTemplate hibernateTemplate = new HibernateTemplate();
HibernateTransactionManager transactionManager = new HibernateTransactionManager(HibernateSessionFactory.getSessionFactory());
hibernateTemplate.setSessionFactory(HibernateSessionFactory.getSessionFactory());
hibernateTemplate.afterPropertiesSet();
transactionManager.afterPropertiesSet();

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				Message message = new Message();
				message.setHibernateTemplate(hibernateTemplate);

				message.setText("Hello World");
				message.create();

				List<Message> list = message.findAll();
				System.out.println(list.size() + "message(s) found");
			}
		});

HibernateSessionFactory.getSessionFactory().close();

テストが终わってからですが、実际の开発はちょっと不便だと思います.entityコードを修正するには、バイトコードを再修正する必要があります.antを使うと便利ですが、entityにビジネス方法を追加しなければ、entityを修正する機会が少なく、受け入れられます.entityにビジネス方法を追加し、充血モデルを豊富にしたいなら、ちょっと面倒です.
しかし、lombokから、eclipseでjavaコードをコンパイルするときに、バイトコードを追加したり、lombokのコードを見たり、複雑なものがあったりする解決策を学びました.後で実現する時間がある...