Scala特征允许将新行为混合到一个类中。 考虑两个特征,可以向JPA实体添加审核和与版本相关的字段:
package mvcsample.domainimport javax.persistence.Version
import scala.reflect.BeanProperty
import java.util.Datetrait Versionable {@Version@BeanPropertyvar version: Int = _
}trait Auditable {@BeanPropertyvar createdAt: Date = _@BeanPropertyvar updatedAt: Date = _
}
现在将“ Versionable”和“ Auditable”及其成员实体中的字段和行为混合在一起:
@Entity
@Table(name = 'members')
class Member(f: String, l: String) extends BaseDomain with Auditable with Versionable {def this() = this(null, null)@BeanPropertyvar first: String = f@BeanPropertyvar last: String = l@OneToMany(fetch = FetchType.EAGER, mappedBy = 'member')@BeanPropertyvar addresses: java.util.List[Address] = _
}trait BaseDomain {@BeanProperty@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = 'id')@Idvar id: Long = 0
}
现在,上面的Member类将具有BaseDomain类的行为,并且将具有Versionable特性和Auditable特性的行为。 普通的Java无法实现这种混合,因为具有字段和行为的特征等同于一个抽象(或具体)类,而Java只允许从1个基类派生。 但是,使用AspectJ可以实现等效的mixin。 考虑使用Aspectj语言定义的以下方面:
package mvcsample.aspect;import javax.persistence.Column;
import javax.persistence.Version;
import mvcsample.annot.Versioned;public interface Versionable {static aspect VersionableAspect {declare parents: @Versioned mvcsample.domain.* implements Versionable;@Version@Column(name = 'version')private Integer Versionable.version; public Integer Versionable.getVersion() {return this.version;}public void Versionable.setVersion(Integer version) { this.version = version;}}
}package mvcsample.aspect;import java.util.Date;
import javax.persistence.Column;import mvcsample.annot.Audited;
public interface Auditable {static aspect AuditableAspect {declare parents: @Audited mvcsample.domain.* implements Auditable ;@Column(name='created_at')private Date Auditable.createdAt;@Column(name='updated_at')private Date Auditable.updatedAt;public Date Auditable.getCreatedAt(){return this.createdAt;}public void Auditable.setCreatedAt(Date createdAt) {this.createdAt = createdAt;}public Date Auditable.getUpdatedAt(){return this.updatedAt;}public void Auditable.setUpdatedAt(Date updatedAt) {this.updatedAt = updatedAt;}}
}
“声明父母:@Versioned mvcsample.domain。*实现了Versionable;” Aspectj构造将'Versionable'接口作为父级添加到包'mvcsampple.domain'中以@Versioned注释的任何类中,类似于'Auditable'的类。 然后,该方面着手将字段添加到Versionable接口中,该接口又最终将字段添加(混合)到目标实体类中,这样,与Audit相关和Version相关的字段和方法将被混合到实体类中。 定义了这两个方面后,目标实体类将如下所示:
@Entity
@Table(name="members")
@Access(AccessType.FIELD)
@Versioned
@Audited
public class Member extends BaseDomain{public Member(){}public Member(String first, String last){this.first = first;this.last = last;}private String first;@Size(min=1)private String last;@OneToMany(fetch=FetchType.EAGER, mappedBy="member")private List<address>addresses = new ArrayList<>();.....
}
</address>
Versionable和Auditable方面中定义的字段和行为将混入该实体(更一般地,混入具有@Versioned和@Audited批注的任何实体)。 可能不如Scala特质那么干净,但效果很好。
参考: Java与Aspects中的Mixin –在all和杂类博客上获取我们JCG合作伙伴 Biju Kunjummen 的Scala特性示例 。
翻译自: https://www.javacodegeeks.com/2013/01/mixin-in-java-with-aspects-for-a-scala-traits-sample.html