Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle properties of type URI with spring data jpa?

Assume there is an entity

@Entity
public class Article {
 // ...
  private String uri;

  public void setUri(URI uri) {
    this.uri = uri.toString();
  }

  public URI getUri() {
    return URI.create(uri.toString();
  }
}

and a spring data jpa repository

public interface ArticleRepository extends CrudRepository<Article, Long> {
    Optional<Article> findByLink(URI link);
}

but using the findByLink(URI) method fails with InvalidDataAccessApiUsageException: Parameter value [http://foo.de/foo.html] did not match expected type [java.lang.String (n/a)]. This can ofcourse be avoided by changing the parameter type to string. But then every URI has to be converted to a string before querying.

What is the best way to handle properties of type URI if you have to query them with spring data jpa?

like image 391
gregor Avatar asked Nov 18 '15 13:11

gregor


People also ask

Which is better CrudRepository or JpaRepository?

Crud Repository doesn't provide methods for implementing pagination and sorting. JpaRepository ties your repositories to the JPA persistence technology so it should be avoided. We should use CrudRepository or PagingAndSortingRepository depending on whether you need sorting and paging or not.

What is @modifying in JPA?

It's a feature of Spring Data JPA @Modifying queries that provides us with the number of updated entities.

What is the return type of findById in JPA?

Its findById method retrieves an entity by its id. The return value is Optional<T> . Optional<T> is a container object which may or may not contain a non-null value. If a value is present, isPresent returns true and get returns the value.

What is @query used for spring?

The @Query annotation can only be used to annotate repository interface methods. The call of the annotated methods will trigger the execution of the statement found in it, and their usage is pretty straightforward. The @Query annotation supports both native SQL and JPQL.


1 Answers

In your current configuration you are trying to apply a URI parameter to a string field. That fails for obvious reasons

Option 1

You change your field to take an URI as well and register a converter to convert a URI to the DB representation.

That would look something like this:

@Converter(autoApply = true)
public class UriPersistenceConverter implements AttributeConverter<URI, String> {

    @Override
    public String convertToDatabaseColumn(URI entityValue) {
        return (entityValue == null) ? null : entityValue.toString();
    }

    @Override
    public URI convertToEntityAttribute(String databaseValue) {
        return (StringUtils.hasLength(databaseValue) ? URI.create(databaseValue.trim()) : null);
    }
}

With this converter you can change the field to URI as well:

@Entity
public class Article {
 // ...
  private URI uri;

  public void setUri(URI uri) {
    this.uri = uri;
  }

  public URI getUri() {
    return this.uri;
  }
}

Option 2

I tried option 1 and can confirm it is working - but Option 2 is theoretical - I think you are using JPA field access - so JPA accesses your entity using the fields - I think if you change the access to PROPERTY JPA should use your getters and setters - they have the correct type so your code could work then.

The access type is inferred using the location of your mapping annotations. If you annotate the fields you get field access - if you annotate your getters you get property access. There is also an entity level annotation to set the access level javax.persistence.Access

@Access(PROPERTY)

Try to annotate your entity with the annotation above and give it a try.

like image 167
Mathias Dpunkt Avatar answered Sep 28 '22 08:09

Mathias Dpunkt