Htea
Htea

Reputation: 1318

Spring Jpa Specification unable to locate attribute in sub classes

so I have following hierarchy of entities:

@MappedSuperClass
public abstract class BaseEntity {
    private Long id;
    private Date createAt;
    private Date updateAt;
}

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Post extends BaseEntity {
    private String creatorId;
    private String title;
    private String content;
}

@Entity
public class Article extends Post {
    private String category;  // article has category
}

@Entity
public class Journal extends Post {
    private Date expiration;  // journal has expiration
}

now when I use Spring Jpa Specification to query for articles with certain category, it won't work:

// define specification
public class ArticleSpecifications {
    public static Specification<Article> withCategory(String category) {
        (root, query, criteriaBuilder) ->
                criteriaBuilder.equal(root.get("category"), category)
    }
}

// repository
public interface PostRepository<T extends Post> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> { ... }


// usage: in some service class
@Autowired
private PostRepository<Article> articleRepository;
...

public void someMethod {
    ...
    // error here
    articleRepository.findAll(ArticleSpecifications.withCategory("news"), pageable);
    ...
}

Error message:

java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [category] on this ManagedType [com.gladdev.galahad.base.BaseEntity]

Just trying to understand here why it tries to look up "category" in BaseEntity.
Every Specification accessing attributes defined in Post works just fine.
Is it some spring jpa specification bug or I missed something?

Upvotes: 3

Views: 1735

Answers (1)

İsmail Y.
İsmail Y.

Reputation: 3965

You can use the CriteriaBuilder.treat() method.

In Criteria API, downcasting an entity to a subclass entity can be performed by using one of the CriteriaBuilder.treat() methods:

See https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html#treat-javax.persistence.criteria.Root-java.lang.Class-

public static Specification<Article> withCategory(String category) {
   return (root, query, criteriaBuilder) -> {
      Root<Article> article = criteriaBuilder.treat(root, Article.class);
      return criteriaBuilder.equal(article.get("category"), category);
   };
}

Upvotes: 1

Related Questions