我正在使用Hibernate并且当前正在使用setter在创建时设置子节点中父节点的关系(以避免双方手动执行此操作)。我如何避免使用setter或避免将其暴露给其他类并获得相同的行为。使用反射可以吗?这是代码:
@Entity
@Table(name = "TEST_GROUP")
@Getter
public class TestGroupEntity extends AuditedEntity{
@ManyToOne
@JoinColumn(name = "owner", nullable = false)
protected UserEntity owner;
@Column(name = "description")
@Setter
protected String description;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
protected Set<TestEntity> tests = Sets.newHashSet();
public boolean addTest(TestEntity testEntity) {
return tests.add(testEntity);
}
public boolean removeTest(TestEntity testEntity) {
return tests.remove(testEntity);
}
public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
this.owner = owner;
owner.setTestGroupEntity(this); ! how to avoid creation of setter
this.tests = tests;
tests.stream().forEach(t -> t.setTestGroupEntity(this)); ! how to avoid creation of setter
}
}
这是儿童班(我希望在api级别保持不变性):
@MappedSuperclass
@AllArgsConstructor
public class TestEntity extends AuditedEntity {
@Column(name = "name", nullable = false)
protected String name;
@Column(name = "description")
protected String description;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "test_group", nullable = false)
protected TestGroupEntity testGroupEntity;
public void setTestGroupEntity(TestGroupEntity testGroupEntity) {
this.testGroupEntity = testGroupEntity;
}
}
编辑:我认为评论的代码部分不可见。遗憾。
答案 0 :(得分:1)
如何避免使用setter或避免将其暴露给其余部分 类和获得相同的行为。可以使用反射吗?
当然,您可以将public setter
的可见性降低到低于public
的可见性,以便实体的客户端类无法使用它们。
在您的情况下,这是真正的问题,因为无论如何都可以从对象内部访问任何数据
来自hibernate doc :
无需声明属性(字段或getter / setter) 上市。 Hibernate可以处理用public声明的属性, 受保护,包裹或私人可见性。再次,如果想要使用 运行时代理生成,用于延迟加载的可见性 getter / setter至少应该是包的可见性。
因此,尝试将private setter
用于所需的字段。它应该解决你的问题。
评论后更新
您有几种解决方法可以解决您的问题:
使用反射(你的基本想法) 缺点:它带来了一点复杂性,而不是在编译时进行全面检查,最后,看到你代码的人可能想知道你为什么使用它... 任何依赖于反射的概念(如AOP)都是一样的。
将这些setters
声明为package-private
级别,并将3个类放在同一个package
中。
缺点:使用过的包。
创建public
init methods
,如果它对同一个对象使用了多次,则会引发异常。通过这种方式,如果使用不当,您可以保证对象的一致性。
缺点:客户不应使用的方法仍然提供给客户。
不幸的是,由于Java可见性机制无法为您所寻找的内容提供现成的解决方案,因此您没有一个完美的解决方案。
就个人而言,我更喜欢反射或初始化方法解决方案。
就个人而言,我注意到在基础类语言中作为Java,一个优秀的开发人员通常会反复过度保护对象/方法的可访问性。事实上,在许多情况下,它不是必需的,因为它不会破坏应用程序或数据的完整性。
这是一个使用init方法的例子:
public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
this.owner = owner;
owner.constructInit(this);
this.tests = tests;
tests.stream().forEach(t -> t.constructInit(this));
}
public class UserEntity {
private TestGroupEntity testGroupEntity;
public void constructInit(TestGroupEntity testGroupEntity) {
if (this.testGroupEntity != null) {
throw new IllegalArgumentException("forbidden");
}
this.testGroupEntity=testGroupEntity;
}
}
答案 1 :(得分:0)
在父类中创建一个构造函数并从子函数中调用它。
这是父构造函数看起来像
public AuditedEntity(UserEntity owner, Set<TestEntity> tests){
this.owner = owner;
this.tests = tests;
}
并改变您的子构造函数,如
public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
super(owner,tests);
}