Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support @Convert specification on id attributes #207

Open
reda-alaoui opened this issue Jan 30, 2019 · 12 comments
Open

Support @Convert specification on id attributes #207

reda-alaoui opened this issue Jan 30, 2019 · 12 comments

Comments

@reda-alaoui
Copy link

reda-alaoui commented Jan 30, 2019

We want to map an id attribute to an immutable type.

class FooId implements Serializable {
    private final int value;

    private FooId(int value) {
      this.value = value;
    }

    public static FooId of(int value) {
      return new FooId(value);
    }

    public int value() {
      return value;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      FooId fooId = (FooId) o;
      return value == fooId.value;
    }

    @Override
    public int hashCode() {
      return Objects.hash(value);
    }
  }

class Converter implements AttributeConverter<FooId, Integer> {

    @Override
    public Integer convertToDatabaseColumn(FooId attribute) {
      return Optional.ofNullable(attribute).map(FooId::value).orElse(null);
    }

    @Override
    public FooId convertToEntityAttribute(Integer dbData) {
      return Optional.ofNullable(dbData).map(FooId::of).orElse(null);
    }
  }

@Entity
class Foo {
   @Id
    @Convert(converter = Converter.class)
    @Column(definition = "integer")
    private FooId id;
}

Hibernate 5 fails to convert the id to the immutable type.

Reading the JPA 2.1 spec, we found this:

The Convert annotation should not be used to specify conversion of the following: Id attributes
(including the attributes of embedded ids and derived identities), version attributes, relationship
attributes, and attributes explicitly annotated (or designated via XML) as Enumerated or Temporal. Applications that specify such conversions will not be portable

Would it be possible to reconsider this to make convert on id attributes a use case part of the next version of JPA?

@andyjefferson
Copy link

andyjefferson commented Jan 30, 2019

There are two separate things here.

  1. Support specification of @Convert on an "id" attribute.
  2. Support use of @Convert when an attribute is generated, and define what is the expected behaviour in that case; if it is generated in the datastore, or if it is generated in Java.

They are distinct, so you should separate this issue out into 2.
There should be a separate issue in this tracker for supporting @GeneratedValue on non-@Id attributes.

@reda-alaoui reda-alaoui changed the title Allow @Convert usage on id attributes Support @Convert spêcification on id attributes Feb 1, 2019
@reda-alaoui reda-alaoui changed the title Support @Convert spêcification on id attributes Support @Convert specification on id attributes Feb 1, 2019
@reda-alaoui
Copy link
Author

reda-alaoui commented Feb 1, 2019

Hi @andyjefferson ,

In fact, Hibernate 5 fails in any case.
For the non generated id case, Hibernate auto ddl was creating a column of type bytes to serialize (java native serialization) the immutable object. I edited my first message to reflect this.

Anyway, I will create a separate issue for the generated value case.

@Rabz2210
Copy link

Rabz2210 commented Oct 2, 2020

@andyjefferson @reda-alaoui Do we have any support for this now?. I see the issue is quite old.
I have been trying @convert of @id attribute whose values is @generate by the datastore. it fails to work.

@reda-alaoui
Copy link
Author

@andyjefferson isn’t the current issue opened on the jakarta jpa specification project?

@gavinking
Copy link
Contributor

Similar to #208.

@BearKid
Copy link

BearKid commented Oct 26, 2023

In order to write clean and readable code, I try to use wrapped Id object and avoid primitive String/Integer Id, but as reda-alaoui said, the code below doesn't work.

@Entity
class ExampleEntity {
    @Id
    @Column(name= "fd_id")
    @Convert(converter = ExampleIdConverter.class)
    private ExampleId id;

    @Value(staticConstructor = "of")
    public static class ExampleId implements Serializable {
        String idAsString;
    }
}

I'm currently using @EmbeddedId to achieve wrapped Id.

@Entity
@Table(name = "example_table")
public class ExampleEntity {
    @EmbeddedId
    @AttributeOverride(name = "idAsString", column = @Column(name = "fd_id"))
    private ExampleId id;


    @Embeddable
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @Getter
    @EqualsAndHashCode
    @AllArgsConstructor(staticName = "of")
    public static class ExampleId implements Serializable {
        private String idAsString;
    }
}

But I think this is less easy to use than the @ Convert & AttributeConverter proposal.
In order for the @EmbeddedId solution to work, those are required:

  1. @EmbeddedId instead of @ Id
  2. @AttributeOverride. I need it because the ExampleId may be used in other Entities where the attribute names mapped to the table columns are not always the same. However filling in name = "idAsString" is a maintenance burden, which requires me to keep an eye on whether the value matches the attribute name in the ExampleId. It leaves an opportunity to make a mistake.
  3. Adding a public/protected no-arg constructor to the wrapped Id class, which I do not need, but JPA requires it.

Hi @reda-alaoui , as of now, do you know of any viable ways for implementing single-attribute wrapper ID? Looking forward to hearing about others' experiences with this.

@reda-alaoui
Copy link
Author

@BearKid , I have been using primitive id since. I don't know how things evolved in between.

@gavinking
Copy link
Contributor

As far as I know, no product implements this (since it's actually pretty hard to implement) so it's not something we plan to add to the spec at this time.

@thiagochaves
Copy link

I wanted to point out that in Hibernate 5.6.15.Final it is possible to use @convert on a @id attribute. I have been doing that for quite some time, exactly to map immutable wrappers to my ids. Now that I'm upgrading Hibernate to version 6.4 is that I found out that it no longer works and was "forbidden" by the JPA specs.

@beikov
Copy link

beikov commented Feb 21, 2024

If you think you found a bug or want to request a feature in Hibernate ORM, please do that through the Hibernate ORM community channels. This is not the proper place for that sort of discussion.

@robmv
Copy link

robmv commented Jun 4, 2024

As far as I know, no product implements this (since it's actually pretty hard to implement) so it's not something we plan to add to the spec at this time.

Revisiting my code in order to see if I can remove a Hibernate Type that is a duplicate implementation of another JPA converter, and find that JPA still doesn't allow Convert on Id fields. My use case is for accessing legacy tables that use CHAR(N) columns as PK, the idea is to strip the ending spaces of the Id at read time and avoid needing to strip the id on every usage site.

@gavinking, You are right that no other implementation allows Convert on Id fields, but Hibernate allows Type on Id fields without any problem.

@gavinking
Copy link
Contributor

@gavinking, You are right that no other implementation allows Convert on Id fields, but Hibernate allows Type on Id fields without any problem.

Correct, and the reason is because a Type tells us much more about the semantics of the thing than an AttributeConverter does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants