Question

Is there any jpa 1.0 fluent api/interface for query building? I'm using openjpa 1.x, so I'm stuck with JPA1.

I found QueryByProxy, but its maven repo is not working properly.

Was it helpful?

Solution

If you're stuck with JPA 1.0, then consider using Querydsl that provides a fluent typesafe API on top of JPA. You'll have to use a version prior to 1.6.0, i.e. 1.5.4 (they switched to JPA 2.0 in 1.6.0). This is IMO your best option.

OTHER TIPS

Short answer is no. However it depends on the provider you are using. For instance if you are using Hibernate, you can always get the Criteria api from hibernate. However in JPA 1.0 this is not supported. In JPA 2.0 however it is.

You can use the Fluent Interface Pattern with JPA and Hibernate. I wrote an article which explains this topic in great detail.

To summarize it, if you're using Hibernate, you can just modify the setters to return the entity:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    private Long id;

    private String title;

    public Post() {}

    public Post(String title) {
        this.title = title;
    }

    @OneToMany(
        cascade = CascadeType.ALL, 
        orphanRemoval = true, 
        mappedBy = "post"
    )
    private List<PostComment> comments = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public Post setId(Long id) {
        this.id = id;
        return this;
    }

    public String getTitle() {
        return title;
    }

    public Post setTitle(String title) {
        this.title = title;
        return this;
    }

    public List<PostComment> getComments() {
        return comments;
    }

    public Post addComment(PostComment comment) {
        comment.setPost(this);
        comments.add(comment);
        return this;
    }
}

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    private Date createdOn;

    @ManyToOne
    private Post post;

    public Long getId() {
        return id;
    }

    public PostComment setId(Long id) {
        this.id = id;
        return this;
    }

    public String getReview() {
        return review;
    }

    public PostComment setReview(String review) {
        this.review = review;
        return this;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

    public PostComment setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
        return this;
    }

    public Post getPost() {
        return post;
    }

    public PostComment setPost(Post post) {
        this.post = post;
        return this;
    }
}

This way, you can build the parent and the child entities like this:

doInJPA(entityManager -> {
    Post post = new Post()
    .setId(1L)
    .setTitle("High-Performance Java Persistence")
    .addComment(
        new PostComment()
        .setReview("Awesome book")
        .setCreatedOn(Timestamp.from(
            LocalDateTime.now().minusDays(1).toInstant(ZoneOffset.UTC))
        )
    )
    .addComment(
        new PostComment()
        .setReview("High-Performance Rocks!")
        .setCreatedOn(Timestamp.from(
            LocalDateTime.now().minusDays(2).toInstant(ZoneOffset.UTC))
        )
    )
    .addComment(
        new PostComment()
        .setReview("Database essentials to the rescue!")
        .setCreatedOn(Timestamp.from(
            LocalDateTime.now().minusDays(3).toInstant(ZoneOffset.UTC))
        )
    );
    entityManager.persist(post);
});

If you care about JPA portability, then you might not want to violate the Java Bean specification, in which case you need to add the Fluent Interface methods along the regular setters:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    private Long id;

    private String title;

    public Post() {}

    public Post(String title) {
        this.title = title;
    }

    @OneToMany(
        cascade = CascadeType.ALL, 
        orphanRemoval = true, 
        mappedBy = "post"
    )
    private List<PostComment> comments = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Post id(Long id) {
        this.id = id;
        return this;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Post title(String title) {
        this.title = title;
        return this;
    }

    public List<PostComment> getComments() {
        return comments;
    }

    public Post addComment(PostComment comment) {
        comments.add(comment.post(this));
        return this;
    }
}

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    private Date createdOn;

    @ManyToOne
    private Post post;

    public Long getId() {
        return id;
    }

    public PostComment setId(Long id) {
        this.id = id;
        return this;
    }

    public String getReview() {
        return review;
    }

    public void setReview(String review) {
        this.review = review;
    }

    public PostComment review(String review) {
        this.review = review;
        return this;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    public PostComment createdOn(Date createdOn) {
        this.createdOn = createdOn;
        return this;
    }

    public Post getPost() {
        return post;
    }

    public void setPost(Post post) {
        this.post = post;
    }

    public PostComment post(Post post) {
        this.post = post;
        return this;
    }
}

The entity building is almost identical to the previous one:

doInJPA(entityManager -> {
    Post post = new Post()
    .id(1L)
    .title("High-Performance Java Persistence")
    .addComment(new PostComment()
        .review("Awesome book")
        .createdOn(Timestamp.from(
            LocalDateTime.now().minusDays(1).toInstant(ZoneOffset.UTC))
        )
    )
    .addComment(new PostComment()
        .review("High-Performance Rocks!")
        .createdOn(Timestamp.from(
            LocalDateTime.now().minusDays(2).toInstant(ZoneOffset.UTC))
        )
    )
    .addComment(new PostComment()
        .review("Database essentials to the rescue!")
        .createdOn(Timestamp.from(
            LocalDateTime.now().minusDays(3).toInstant(ZoneOffset.UTC))
        )
    );
    entityManager.persist(post);
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top