Java 将自定义标识符分配给@id属性

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(

我正在迁移一个遗留系统以使用Hibernate 3。它当前生成自己的标识符。在我尝试将系统移动到更好的位置之前,为了保持系统当前的功能,我应该如何指定(使用注释)自己的类,以便在插入时返回自定义生成的标识符

比如:

@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指出错误。检查答案中的更新部分。