Enterprise Java

Test JPQL / HQL without a deploy

Have you ever wanted to test your JPQL / HQL without doing a full deploy of your application?
What we will see here today is simple solution that works for any JPA implementation: Hibernate, OpenJPA, EclipseLink and others.

The base source code found in this post came from this book: “Pro JPA 2: Mastering the Java™ Persistence API – Mike Keith, Merrick Schincariol”. This post will add to the original code: query parameters and NamedQuery test.

Model classes and data Generation

Bellow are the model classes’ code:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
package com.model;
 
import java.util.*;
 
import javax.persistence.*;
 
@Entity
@NamedQueries({
  @NamedQuery(name="Person.findByName", query="select p from Person p where p.name = :name"),
  @NamedQuery(name="Person.findByAge", query="select p from Person p where p.age = :age", hints={@QueryHint(name="org.hibernate.timeout", value="1000")})
})
 
public class Person {
 
 public static final String FIND_BY_NAME = "Person.findByName";
 public static final String FIND_BY_AGE = "Person.findByAge";
 
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int id;
 
 private String name;
 private int age;
 
 public Person() {
 
 }
 
 public Person(int id) {
  this.id = id;
 }
 
 public Person(String name, int age) {
  this.name = name;
  this.age = age;
 }
 
 @OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
 private List<Dog> dogs;
 
 @OneToOne(cascade = CascadeType.ALL)
 @JoinColumn(name="address_id")
 private Address address;
 
 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public int getAge() {
  return age;
 }
 
 public void setAge(int age) {
  this.age = age;
 }
 
 public List<Dog> getDogs() {
  if (dogs == null) {
   dogs = new ArrayList<Dog>();
  }
 
  return dogs;
 }
 
 public void setDogs(List<Dog> dogs) {
  this.dogs = dogs;
 }
 
 public Address getAddress() {
  return address;
 }
 
 public void setAddress(Address address) {
  this.address = address;
 }
 
 @Override
 public int hashCode() {
  return getId();
 }
 
 @Override
 public boolean equals(Object obj) {
  if (obj instanceof Person) {
   Person person = (Person) obj;
   return person.getId() == getId();
  }
 
  return false;
 }
 
 @Override
 public String toString() {
  return "Person name: " + name;
 }
}
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
package com.model;
 
import java.util.Date;
 
import javax.persistence.*;
 
@Entity
@NamedQueries(value={@NamedQuery(name="Dog.FindByDateOfBirth", query="select d from Dog d where d.dateOfBirth = :dateOfBirth"),
  @NamedQuery(name="Dog.FindByPerson", query="select d from Dog d where d.person = :personObject")})
public class Dog {
 
 public static final String FIND_BY_DATE_OF_BIRTH = "Dog.FindByDateOfBirth";
 
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int id;
 
 private String name;
 private double weight;
 
 @Temporal(TemporalType.TIMESTAMP)
 private Date dateOfBirth;
 
 public Dog() {
 
 }
 
 public Dog(String name, double weight, Date dateOfBirth) {
  this.name = name;
  this.weight = weight;
  this.dateOfBirth = dateOfBirth;
 }
 
 public static void main(String[] args) {
 
  System.out.println(new Date());
 }
 
 @ManyToOne
 private Person person;
 
 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public double getWeight() {
  return weight;
 }
 
 public void setWeight(double weight) {
  this.weight = weight;
 }
 
 public Date getDateOfBirth() {
  return dateOfBirth;
 }
 
 public void setDateOfBirth(Date dateOfBirth) {
  this.dateOfBirth = dateOfBirth;
 }
 
 public Person getPerson() {
  return person;
 }
 
 public void setPerson(Person person) {
  this.person = person;
 }
 
 @Override
 public int hashCode() {
  return getId();
 }
 
 @Override
 public boolean equals(Object obj) {
  if (obj instanceof Dog) {
   Dog dog = (Dog) obj;
   return dog.getId() == getId();
  }
 
  return false;
 }
 
 @Override
 public String toString() {
  return "Dog name: " + name;
 }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.model;
 
import javax.persistence.*;
 
@Entity
@NamedQuery(name="Address.FindAll", query="select a from Address a")
public class Address {
 
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int id;
 
 private String streetName;
 private int houseNumber;
 
 public Address() {
 
 }
 
 public Address(String streetName, int houseNumber) {
  this.streetName = streetName;
  this.houseNumber = houseNumber;
 }
 
 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }
 
 public String getStreetName() {
  return streetName;
 }
 
 public void setStreetName(String streetName) {
  this.streetName = streetName;
 }
 
 public int getHouseNumber() {
  return houseNumber;
 }
 
 public void setHouseNumber(int houseNumber) {
  this.houseNumber = houseNumber;
 }
 
 @Override
 public int hashCode() {
  return getId();
 }
 
 @Override
 public boolean equals(Object obj) {
  if (obj instanceof Address) {
   Address address = (Address) obj;
   return address.getId() == getId();
  }
 
  return false;
 }
 
 @Override
 public String toString() {
  return "Adress street name: " + streetName;
 }
}

In the code above we got several JPA relationships as a sample.

Bellow is the class that will handle the transaction and the data that will be written into the HSQLDB database:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.main;
 
import java.text.*;
import java.util.Date;
 
import javax.persistence.*;
 
import com.model.*;
 
public class CodeGenerator {
 private static EntityManagerFactory emf;
 private static EntityManager em;
 
 public static final String PERSON01_NAME = "John";
 public static final String PERSON02_NAME = "Mary";
 public static final String PERSON03_NAME = "Anna";
 public static final String PERSON04_NAME = "Joseph";
 public static final String PERSON05_NAME = "Mark";
 public static final String PERSON06_NAME = "I will not have any relationship";
 
 public static void startConnection() {
  emf = Persistence.createEntityManagerFactory("QueryTester");
  em = emf.createEntityManager();
  em.getTransaction().begin();
 }
 
 public static void closeConnection() {
  em.getTransaction().commit();
  emf.close();
 }
 
 public static void generateData() {
  int year = 1995;
  int month = 1;
  int day = 10;
 
  Dog dog01 = new Dog("Yellow", 3.5d, createNewDate(day, month, year));
  Dog dog02 = new Dog("Brown", 8.5d, createNewDate(++day, ++month, ++year));
  Dog dog03 = new Dog("Dark", 15.5d, createNewDate(++day, ++month, ++year));
  Dog dog04 = new Dog("Kaka", 4.3d, createNewDate(++day, ++month, ++year));
  Dog dog05 = new Dog("Pepe", 8.2d, createNewDate(++day, ++month, ++year));
  Dog dog06 = new Dog("Casillas", 6.1d, createNewDate(++day, ++month, ++year));
  Dog dog07 = new Dog("Fish", 6.7d, createNewDate(++day, ++month, ++year));
  Dog dog08 = new Dog("Lion", 3.1d, createNewDate(++day, ++month, ++year));
  Dog dog09 = new Dog("Cat", 5.5d, createNewDate(++day, ++month, ++year));
  Dog dog10 = new Dog("Java", 21.7d, createNewDate(++day, ++month, ++year));
  Dog dog11 = new Dog("JSF", 23.65d, createNewDate(++day, ++month, ++year));
  Dog dog12 = new Dog("VRaptor", 24.0d, createNewDate(++day, ++month, ++year));
  Dog dog13 = new Dog("Ferrari", 3.7d, createNewDate(++day, ++month, ++year));
  Dog dog14 = new Dog("Porshe", 1.33d, createNewDate(++day, ++month, ++year));
  Dog dog15 = new Dog("Bike", 4.44d, createNewDate(++day, ++month, ++year));
  Dog dog16 = new Dog("Rambo", 5.44d, createNewDate(++day, ++month, 2015));
  Dog dog17 = new Dog("Terminator", 3.88d, createNewDate(++day, ++month, 2016));
  Dog dog18 = new Dog("John McClan", 3.88d, createNewDate(++day, ++month, 2016));
 
  Person person01 = new Person(PERSON01_NAME, 33);
  person01.getDogs().add(dog01);
  person01.getDogs().add(dog02);
  person01.getDogs().add(dog03);
  person01.setAddress(new Address("Street A", 30));
  dog01.setPerson(person01);
  dog02.setPerson(person01);
  dog03.setPerson(person01);
 
  Person person02 = new Person(PERSON02_NAME, 27);
  person02.getDogs().add(dog04);
  person02.getDogs().add(dog05);
  person02.getDogs().add(dog06);
  person02.setAddress(new Address("Street B", 60));
  dog04.setPerson(person02);
  dog05.setPerson(person02);
  dog06.setPerson(person02);
 
  Person person03 = new Person(PERSON03_NAME, 7);
  person03.getDogs().add(dog07);
  person03.getDogs().add(dog08);
  person03.getDogs().add(dog09);
  person03.setAddress(new Address("Street B", 90));
  dog07.setPerson(person03);
  dog08.setPerson(person03);
  dog09.setPerson(person03);
 
  Person person04 = new Person(PERSON04_NAME, 43);
  person04.getDogs().add(dog10);
  person04.getDogs().add(dog11);
  person04.getDogs().add(dog12);
  person04.setAddress(new Address("Street C", 120));
  dog10.setPerson(person04);
  dog11.setPerson(person04);
  dog12.setPerson(person04);
 
  Person person05 = new Person(PERSON05_NAME, 70);
  person05.getDogs().add(dog13);
  person05.getDogs().add(dog14);
  person05.getDogs().add(dog15);
  person05.getDogs().add(dog16);
  person05.setAddress(new Address("Street D", 150));
  dog13.setPerson(person05);
  dog14.setPerson(person05);
  dog15.setPerson(person05);
  dog16.setPerson(person05);
 
  Person person06 = new Person(PERSON06_NAME, 45);
 
  em.persist(person01);
  em.persist(person02);
  em.persist(person03);
  em.persist(person04);
  em.persist(person05);
  em.persist(person06);
 
  em.persist(dog17);
  em.persist(dog18);
 
  em.flush();
 }
 
 private static Date createNewDate(int day, int month, int year) {
  SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
  try {
   return formatter.parse("" + day + "/" + month + "/" + year);
  } catch (ParseException e) {
   e.printStackTrace();
   return null;
  }
 }
 
 public static EntityManager getEntityManager() {
  return em;
 }
}

The “persistence.xml” file can be found in the “src/META-INF” folder with the code bellow:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
 
<persistence version="2.0"
 
 <persistence-unit name="QueryTester"
  transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
 
  <properties>
   <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
   <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:." />
   <property name="javax.persistence.jdbc.user" value="sa" />
   <property name="javax.persistence.jdbc.password" value="" />
   <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
   <property name="hibernate.connection.shutdown" value="true" />
   <property name="hibernate.hbm2ddl.auto" value="update" />
   <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.format_sql" value="false"/>
  </properties>
 </persistence-unit>
</persistence>

Abstract test class

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.main;
 
import javax.persistence.Query;
 
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
 
import com.model.Person;
 
/**
 * @author Pro JPA 2 book
 * @Empowered by uaiHebert
 *
 */
public abstract class AbstractQueryTester {
 
 protected static void populateParameters(Query query, String parameters) {
  for (String parameter : parameters.split(";")) {
   String parameterKey = parameter.split("-")[0];
   String parameterValue = parameter.split("-")[1];
   String parameterType = parameter.split("-")[2];
 
   query.setParameter(parameterKey, configureParameterValue(parameterValue, parameterType));
  }
 }
 
 private static Object configureParameterValue(String parameterValue, String parameterType) {
  if (parameterType.equalsIgnoreCase("integer")) {
   try {
    return Integer.parseInt(parameterValue);
   } catch (Exception e) {
    throw new IllegalArgumentException("Invalid parameter value as number: " + parameterValue);
   }
  }
 
  if (parameterType.equalsIgnoreCase("string")) {
   return parameterValue;
  }
 
  if (parameterType.equalsIgnoreCase("person")) {
   int personId;
 
   try {
    personId = Integer.valueOf(parameterValue);
   } catch (Exception e) {
    throw new IllegalArgumentException("Invalid parameter value as number: " + parameterValue);
   }
 
   return new Person(personId);
  }
 
  throw new IllegalArgumentException("Invalid parameter type: " + parameterType);
 }
 
 protected static void printResult(Object result) throws Exception {
  if (result == null) {
   System.out.print("NULL");
  } else if (result instanceof Object[]) {
   Object[] row = (Object[]) result;
   System.out.print("[");
   for (int i = 0; i < row.length; i++) {
    printResult(row[i]);
   }
   System.out.print("]");
  } else if (result instanceof Long || result instanceof Double || result instanceof String) {
   System.out.print(result.getClass().getName() + ": " + result);
  } else {
   System.out.print(ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE));
  }
 
  System.out.println();
 }
}

About the above code:

  • The populateParameters method will populate all query parameters automatically. The Eclipse console will require that the developer type the Query information and the Query parameters if any is required. The Query parameters should follow the syntax requirements bellow:
    • 0 parameters: just press “Enter”
    • 1 parameter: id-4-integer
    • 2 or more parameters: name-John-string;age-33-integer
    • The developer may use class as parameter: dog-33-Dog
  • The configureParameterValue method will “cast” the parameterValue to the correct type required by the Query. It allows primitive values and classes.
  • The printResult method will display the Query result.

Dynamic Query test

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.main;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.Query;
 
/**
 * @author Pro JPA 2 book
 * @Empowered by uaiHebert
 *
 */
public class DynamicQueryTester extends AbstractQueryTester {
 public static void main(String[] args) throws IOException {
  CodeGenerator.startConnection();
 
  CodeGenerator.generateData();
 
  EntityManager em = CodeGenerator.getEntityManager();
 
  BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 
  for (;;) {
   System.out.print("Type your JPQL and press Enter > ");
   String dynamicQuery = reader.readLine();
 
   if (dynamicQuery.equals("quit")) {
    break;
   }
 
   if (dynamicQuery.length() == 0) {
    continue;
   }
 
   System.out.println("Type the namedQuery parameters.");
   System.out.println("All paramters should be like: id-2-integer;name-John-string");
   System.out.println("Or just press enter for 0 parameters");
   String parameters = reader.readLine();
 
   try {
    Query query = em.createQuery(dynamicQuery);
 
    if (parameters.length() > 0) {
     populateParameters(query, parameters);
    }
 
    @SuppressWarnings("rawtypes")
    List result = query.getResultList();
 
    if (result.size() > 0) {
     int count = 0;
     for (Object o : result) {
      System.out.print(++count + " ");
      printResult(o);
     }
    } else {
     System.out.println("0 results returned");
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 
  CodeGenerator.closeConnection();
 }
}

The code above will start a transaction, create the database data in runtime memory and allow a developer to test any kind of dynamic query. To test a JPQL / HQL the developer just need to type the Query code in the console.

To finish the loop do not type any Query data, just type “quit” and press “Enter”.

NamedQuery test
 

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.main;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.Query;
 
/**
 * @author Pro JPA 2 book
 * @Empowered by uaiHebert
 *
 */
public class NamedQueryTester extends AbstractQueryTester {
 public static void main(String[] args) throws IOException {
  CodeGenerator.startConnection();
 
  CodeGenerator.generateData();
 
  EntityManager em = CodeGenerator.getEntityManager();
 
  BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 
  for (;;) {
   System.out.print("Type the NamedQuery name > ");
   String namedQueryName = reader.readLine();
 
   if (namedQueryName.equals("quit")) {
    break;
   }
 
   if (namedQueryName.length() == 0) {
    continue;
   }
 
   System.out.println("Type the namedQuery parameters.");
   System.out.println("Press enter for 0 parameters");
   System.out.println("Or type all paramters like: id-2,name-4");
   String parameters = reader.readLine();
 
   try {
    Query query = em.createNamedQuery(namedQueryName);
 
    if (parameters.length() > 0) {
     populateParameters(query, parameters);
    }
 
    @SuppressWarnings("rawtypes")
    List result = query.getResultList();
 
    if (result.size() > 0) {
     int count = 0;
     for (Object o : result) {
      System.out.print(++count + " ");
      printResult(o);
     }
    } else {
     System.out.println("0 results returned");
    }
   } catch (Exception e) {
    System.err.println(e.getClass() + e.getMessage());
   }
  }
 
  CodeGenerator.closeConnection();
 }
}

The code above will start a transaction, create the database data in runtime memory and allow the test of NamedQueries that are configured in the model classes. To test the NamedQueries just type their name in the console.

To finish the loop do not type any NamedQuery name, just type “quit” and press “Enter”.

Running the application

Run the class DynamicQueryTester and type the following text in the console: “select p from Person p”. Press enter twice and the following text will appear in the console:

At the first “Enter” key hit a message will be displayed asking for parameters if there are any.

Type in the console: “select p from Person p where p.age > :age” and press “Enter”. Type the parameter: “age-69-integer”. Press enter and the result bellow will be displayed:

To finish the code that is running type the word “quit” and press the “Enter” button.

Run now the code of the class NamedQueryTester.

Type the NamedQuery name “Dog.FindByPerson” in the console and press enter. Type “personObject-1-person” parameter and the result bellow will be displayed:

Using this post code with your application code

You can use the code of this post in two ways: add your application model class to the project of this post or use the code found in the main package of this project in your application.

Add your model class to the project of this post:

  • Copy the model class to the “com.model” package.
  • Set up the persistence.xml to access the database

Use the code found in the main package in your application:

  • Set up the PersistenceUnit found in the CodeGenerator class.
  • Use the Apache library found in the libs folder: “commons-lang3-3-1.jar”.

For both approaches the step bellow are required:

  • Edit the method “AbstractQueryTester.configureParameterValue” to accept all attributes values/types/classes that will be used with the queries.
  • Edit the “hibernate.hbm2ddl.auto” configuration to “none” or “validate”. This configuration is found in the “persistence.xml” file.
  • Only invoke the methods to start/close the connection in the CodeGenerator class.

Proposals

Bellow you will find some proposals to do with this code:

  • Use the Reflection technique to create the classes in the “AbstractQueryTester.configureParameterValue” method.
  • Apply Jenkins to validate if some of the JPQLs are with the right syntax after a commit.

The End

I hope this post might help you.

Click here to download the source code of this post.

If you have any doubt/suggestion just post it.

Reference: How to test your JPQL / HQL without a Deploy from our JCG partner Hebert Coelho at the uaiHebert blog.

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Hebert Coelho

Senior Java Development, with 4 certifications and a published book about JSF (portuguese only). Founder of the blog uaiHebert.com visited from more than 170 different countries.
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Johannes Brodwall
12 years ago

This is a nice basic technique, and it could be improved further:

* When testing stuff, JUnit is a nice additional too
* When building test data, it pays off to pay attention to adding convenience constructors and fluent setters to avoid drowning in code.
* The article leaves out the fact that you have to monkey around with the persistence.xml to have one that works when deployed and one that works when running locally.

Back to top button