Scala特征允许将新行为混合到一个类中。 考虑两个特征,可以向JPA实体添加审核和与版本相关的字段:
package mvcsample.domain
import javax.persistence.Version
import scala.reflect.BeanProperty
import java.util.Date
trait Versionable {
@Version
@BeanProperty
var version: Int = _
}
trait Auditable {
@BeanProperty
var createdAt: Date = _
@BeanProperty
var 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)
@BeanProperty
var first: String = f
@BeanProperty
var last: String = l
@OneToMany(fetch = FetchType.EAGER, mappedBy = 'member')
@BeanProperty
var addresses: java.util.List[Address] = _
}
trait BaseDomain {
@BeanProperty
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = 'id')
@Id
var 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