Java 将自定义标识符分配给@id属性
我正在迁移一个遗留系统以使用Hibernate 3。它当前生成自己的标识符。在我尝试将系统移动到更好的位置之前,为了保持系统当前的功能,我应该如何指定(使用注释)自己的类,以便在插入时返回自定义生成的标识符 比如:Java 将自定义标识符分配给@id属性,java,hibernate,jpa,Java,Hibernate,Jpa,我正在迁移一个遗留系统以使用Hibernate 3。它当前生成自己的标识符。在我尝试将系统移动到更好的位置之前,为了保持系统当前的功能,我应该如何指定(使用注释)自己的类,以便在插入时返回自定义生成的标识符 比如: @Id @CustomIdGenerator(Foo.class) // obviously this is not a real annotation public String getId() { ... } 其中,Foo类有一个生成标识符的方法 目前我只是手动调用setId(
@Id
@CustomIdGenerator(Foo.class) // obviously this is not a real annotation
public String getId() { ... }
其中,Foo
类有一个生成标识符的方法
目前我只是手动调用setId(stringid)
方法,但希望找到更好的方法来处理这种情况。您可以
首先,实现org.hibernate.id.IdentifierGenerator
然后必须将其映射到映射xml文件中。我找不到一种使用注释的方法:
<!--
<identifier-generator.../> allows customized short-naming
of IdentifierGenerator implementations.
-->
<!ELEMENT identifier-generator EMPTY>
<!ATTLIST identifier-generator name CDATA #REQUIRED>
<!ATTLIST identifier-generator class CDATA #REQUIRED>
最后,使用@GeneratedValue(generator=“identifier name”)
注意,这是特定于hibernate的(不是JPA)
更新:我查看了Hibernate的源代码,似乎在一个地方,在解析短名称失败后,hibernates尝试调用Class.forName(…)
。那里的参数称为策略
。下面是您尝试的内容:
- 尝试在
属性中将类完全限定名设置为字符串生成器
- 尝试将类fqn设置为
@GenericGenerator
属性中的字符串(使用一些任意名称)strategy
让我知道哪个(如果有的话)有效我认为没有现成的支持使用纯JPA-2 API使用自定义注释生成自定义ID。但是如果您想使用特定于提供者的API,那么这项工作相当简单 要独立于提供商,请尝试以下任何技巧 IdGeneratorHolder
public abstract class IdGeneratorHolder {
/* PersistentEntity is a marker interface */
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
/* sample impelementation */
if(Product.class.isAssignableFrom(entityType)) {
return new ProductIdGenerator();
}
return null;
}
}
public class ProductIdGenerator implements IdGenerator {
public String generate() {
/* some complicated logic goes here */
return ${generatedId};
}
}
特定Id生成器-产品Id生成器
public abstract class IdGeneratorHolder {
/* PersistentEntity is a marker interface */
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
/* sample impelementation */
if(Product.class.isAssignableFrom(entityType)) {
return new ProductIdGenerator();
}
return null;
}
}
public class ProductIdGenerator implements IdGenerator {
public String generate() {
/* some complicated logic goes here */
return ${generatedId};
}
}
现在,在no-arg构造函数中设置生成的id,或者在@PrePersist方法中设置生成的id
Product.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
在上面的示例中,所有ID都是相同的类型,即java.lang.String
。如果持久实体具有不同类型的ID
IdGenerator.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
CustomId.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
Item.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
您还可以使用自定义批注
CustomIdGenerator.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
IdStrategy.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
IdGeneratorHolder.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
public interface IdGenerator {
CustomId generate();
}
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
public @interface CustomIdGenerator {
IdStrategy strategy();
}
enum IdStrategy {
uuid, humanReadable,
}
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
如果我们或其他人(有意或错误地)多次调用@PrePersist带注释的方法,则“唯一id将被更改!!!”因此最好在无参数构造函数中设置id。或者要解决此问题,请执行非空检查
@PrePersist
public void generateId() {
if(id != null)
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
更新
如果我们把id生成放在
没有arg构造函数,不是吗
加载实体时导致问题
从数据库?因为冬眠
将调用无参数构造函数
导致现有ID被删除
重新生成
是的,你是对的,我错过了那部分(实际上,我想告诉您:-在我的应用程序中,每个实体对象都与一个组织实体相关联;因此我创建了一个带有两个构造函数的抽象超类,每个实体(组织除外)都扩展了这个类
protected PersistentEntityImpl() {
}
protected PersistentEntityImpl(Organization organization) {
String entityId = UUIDGenerator.generate();
String organizationId = organization.getEntityId();
identifier = new EntityIdentifier(entityId, organizationId);
}
no-arg构造函数用于JPA提供程序,我们从不调用no-arg构造函数,而是调用另一个基于组织的构造函数。正如您所看到的。id是在基于组织的构造函数中分配的。(在编写答案时,我真的错过了这一点,很抱歉)
看看是否可以在应用程序中实现此策略或类似策略
第二种选择是使用
@预科注释,我把它放进去了
而且这种方法从来没有被击中过
给我一个例外说明我需要
手动设置id。有吗
我还应该做些什么
理想情况下,JPA提供程序应该调用@PrePersist方法(一个在类中声明,另一个在超类中声明)在持久化实体对象之前。除非您显示一些代码和控制台,否则无法告诉您错误所在。我也看到了同样的情况,并希望尽可能避免使用xml文件。但如果找不到替代方法,我想我会使用此方法。谢谢!我在我的id字段中添加了以下注释:@GeneratedValue(generator=“spike.TestIdGenerator”)在启动时导致以下错误:org.hibernate.AnnotationException:未知Id.generator:spike.TestIdGenerator-然后我尝试了以下注释:@GenericGenerator(name=“foo”,strategy=“spike.TestIdGenerator”)这导致在尝试保存时出现此异常:org.hibernate.id.IdentifierGenerationException:调用save()之前必须手动分配此类的id谢谢你的回复!我对你的两个建议都有点困惑。如果我们将id生成放在一个无参数构造函数中,那么从数据库加载实体时不会出现问题吗?因为hibernate将调用无参数构造函数,导致重新生成现有id,这不是我想要的(即使我将空签入)。第二个选项是使用@PrePersist注释。我把它放进去,该方法从未被击中,并给我一个异常,说明我需要手动设置id。我还应该做些什么吗?@digiarnie+1指出错误。检查答案中的更新部分。