Spring Top

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
REST Top

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> CHECK OUT THE COURSE
Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE

1. Overview

In this quick tutorial, we'll discuss the Spring Data Querydsl Web Support.

This is definitely an interesting alternative to all the other ways we focused on in the main REST Query Language series.

2. The Maven Config

First, let's start with our maven configuration:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.0.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
    </dependency>
    <dependency>
        <groupId>com.mysema.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
    </dependency>
    <dependency>
        <groupId>com.mysema.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <version>${querydsl.version}</version>
    </dependency>
...

Note that Querydsl web support is available in spring-data-commons since 1.11

3. The User Repository

Next, let's take a look at our repository:

public interface UserRepository extends 
  JpaRepository<User, Long>, QueryDslPredicateExecutor<User>, QuerydslBinderCustomizer<QUser> {
    @Override
    default public void customize(QuerydslBindings bindings, QUser root) {
        bindings.bind(String.class).first(
          (StringPath path, String value) -> path.containsIgnoreCase(value));
        bindings.excluding(root.email);
    }
}

Note that:

  • We're overriding QuerydslBinderCustomizer customize() to customize the default binding
  • We're customizing the default equals binding to ignore case for all String properties
  • We're also excluding the user's email from Predicate resolution

Check out the full documentation here.

4. The User Controller

Now, let's take a look at the controller:

@RequestMapping(method = RequestMethod.GET, value = "/users")
@ResponseBody
public Iterable<User> findAllByWebQuerydsl(
  @QuerydslPredicate(root = User.class) Predicate predicate) {
    return userRepository.findAll(predicate);
}

This is the interesting part – notice how we're obtaining a Predicate directly out of the HttpRequest, using the @QuerydslPredicate annotation.

Here's how a URL with this type of query would look like:

http://localhost:8080/users?firstName=john

And here's how a potential response would be structure:

[
   {
      "id":1,
      "firstName":"john",
      "lastName":"doe",
      "email":"[email protected]",
      "age":11
   }
]

5. Live Test

Finally, let's test out the new Querydsl Web Support:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class UserLiveTest {

    private ObjectMapper mapper = new ObjectMapper();
    private User userJohn = new User("john", "doe", "[email protected]");
    private User userTom = new User("tom", "doe", "[email protected]");

    private static boolean setupDataCreated = false;

    @Before
    public void setupData() throws JsonProcessingException {
        if (!setupDataCreated) {
            givenAuth().contentType(MediaType.APPLICATION_JSON_VALUE)
                       .body(mapper.writeValueAsString(userJohn))
                       .post("http://localhost:8080/users");
 
            givenAuth().contentType(MediaType.APPLICATION_JSON_VALUE)
                       .body(mapper.writeValueAsString(userTom))
                       .post("http://localhost:8080/users");
            setupDataCreated = true;
        }
    }

    private RequestSpecification givenAuth() {
        return RestAssured.given().auth().preemptive().basic("user1", "user1Pass");
    }
}

First, let's get all users in the system:

@Test
public void whenGettingListOfUsers_thenCorrect() {
    Response response = givenAuth().get("http://localhost:8080/users");
    User[] result = response.as(User[].class);
    assertEquals(result.length, 2);
}

Next, let's find users by first name:

@Test
public void givenFirstName_whenGettingListOfUsers_thenCorrect() {
    Response response = givenAuth().get("http://localhost:8080/users?firstName=john");
    User[] result = response.as(User[].class);
    assertEquals(result.length, 1);
    assertEquals(result[0].getEmail(), userJohn.getEmail());
}

Next, lest find users by partial last name:

@Test
public void givenPartialLastName_whenGettingListOfUsers_thenCorrect() {
    Response response = givenAuth().get("http://localhost:8080/users?lastName=do");
    User[] result = response.as(User[].class);
    assertEquals(result.length, 2);
}

Now, let's try to find users by email:

@Test
public void givenEmail_whenGettingListOfUsers_thenIgnored() {
    Response response = givenAuth().get("http://localhost:8080/users?email=john");
    User[] result = response.as(User[].class);
    assertEquals(result.length, 2);
}

Note: When we try to find user by email – the query was ignored, because we excluded user's email from Predicate resolution.

6. Conclusion

In this article we had a quick intro to the Spring Data Querydsl Web Support and a cool, simple way to obtain a Predicate directly out of the HTTP request and using that to retrieve data.

« Previous
REST Query Language with RSQL
Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
REST bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course :

>> CHECK OUT THE COURSE
Persistence bottom
Get started with Spring Data JPA through the reference Learn Spring Data JPA course: >> CHECK OUT THE COURSE
REST footer banner
13 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are closed on this article!