14

In our entity beans we use a custom ID format which includes a checksum to verify that the ID is actually valid. Ids look like ID827391738979. To make sure that all code uses correct IDs only we created a code wrapper around an ID String:

class ID {
    public ID(String id) {
       // parse and verify ID
    }

    public String toString() {
       return id;
    }
}

All code just uses this ID object. However in our entity we have defined the ID as a String:

class SomeEntity {
    @Column
    private String itsID;
}

Now we want to use Spring-Data-JPA to query some object by it's id. So we do:

public SomeEntity findByItsID(ID itsId);

Problem is, that now Spring Data JPA tries to assign the ID-typed parameter to the query, while the query of course expects a String.

Is it possible to have Spring Data JPA convert the parameter to the expected type (e.g. by registering a Spring converter) before it is inserted into the query? Or, do we have to let the method take a String like this:

public SomeEntity findByItsId(String itsId);

I would rather avoid this, so all code can use the ID class instead of resorting to Strings.

falsarella
  • 12,217
  • 9
  • 69
  • 115
Jan Thomä
  • 13,296
  • 6
  • 55
  • 83

1 Answers1

21

You could use a custom type in your entity with JPA 2.1 @Convert, so JPA makes the conversion for you (I've tested it with Spring Data JPA also, and it worked transparently!), see:

Entity:

@Entity
class SomeEntity {

    @Column(name = "my_id_column_name")
    @Convert(converter = MyIDConverter.class)
    private ID itsID;
}

Converter:

public class MyIDConverter implements AttributeConverter<ID, String> {

    @Override
    public String convertToDatabaseColumn(ItStaticDataKey javaKey) {
        // your implementation here
    }

    @Override
    public ItStaticDataKey convertToEntityAttribute(final String databaseKey) {
        // your implementation here
    }

}

Notes:

  1. Make sure you're using a JPA-2.1-compatible Spring Data JPA version. (I'm sure that Spring Data JPA 1.7.0 (and above) are (or at least should) be compatible).
  2. Unfortunately, it won't work if that field should also be annotated with @Id.
  3. If you use EclipseLink, you have to define converter in persistence.xml, or it doesn't pick it up. https://bugs.eclipse.org/bugs/show_bug.cgi?id=412454.
  4. With JPA on Spring, package containing converters have to appear in property packageToScan on EntityManagerFactoryBean.
falsarella
  • 12,217
  • 9
  • 69
  • 115
  • 1
    Thanks for number 2 been siting with it for two hours – osundblad Apr 11 '16 at 14:46
  • will a converter of type AttributeConverter work? Its doesnt seem to be getting picked up by JPA – Vladimir Jan 07 '18 at 16:15
  • @Vladimir : From `AttributeConverter`s JavaDoc: " A class that implements this interface can be used to convert entity attribute state into database column representation and back again. Note that the X and Y types may be the same Java type." – Peter Wippermann Oct 17 '18 at 14:17
  • 2
    Also you can't have both `@Convert` and `@Enumerated` on the field at the same time (I made this mistake and the converter was not taken into account). – Julien Kronegg Oct 25 '19 at 11:42
  • @falsarella How to deal with multiple datasource configuration ? I am not able to get the property value from properties file when I use multiple datasource configuration. – Krish Aug 25 '20 at 16:26
  • Sorry @Krish I've been focused on frontend for some time. But it looks like your issue is more related to the configuration itself than the converter. – falsarella Aug 25 '20 at 17:40
  • If you add `@Converter(autoApply = true)` to the converter-class, you can omit the `@Convert...` annotation and the converter is used automatically in all places where it fits. – Datz Jun 22 '22 at 10:39