Kohei Nozaki's blog 

Entries tagged [jpa]

JPA Builder パターン


Posted on Sunday Dec 04, 2016 at 12:00AM in Technology


このエントリは Java EE Advent Calendar 2016 の4日目の記事です.


JPA のおかげで,多数のカラムや複雑なリレーションを持つテーブルへのレコード生成は,プレーンな JDBC を使っていた時代に比べると,たいへん楽になりました.しかし,いぜん頭を悩ませる局面もあります.例えば,以下の図のようなスキーマを考えてみてください:

829fc6f6 cccb 44c2 816a b7f397e83309

このスキーマ中の Employee テーブルへレコードを生成するコードを考えてみてください.以下のようになると思います:

public class EmployeeService {

    private final EntityManager em;

    EmployeeService(final EntityManager em) {
        this.em = em;
    }

    public long create(long deptId,
                       String name,
                       boolean temporary,
                       Set<Long> projectIds,
                       Set<String> phoneNumbers) {

        // instantiating and setting attributes of employee
        final Employee employee = new Employee();
        employee.setName(name);
        employee.setTemporary(temporary);
        employee.setProjects(new HashSet<>());
        employee.setPhones(new HashSet<>());

        // making a relation between employee and dept
        final Dept dept = em.find(Dept.class, deptId);
        employee.setDept(dept);
        em.persist(employee);
        dept.getEmployees().add(employee);

        // making relations between employee and projects
        for (final Long projectId : projectIds) {
            final Project project = em.find(Project.class, projectId);
            project.getEmployees().add(employee);
            employee.getProjects().add(project);
        }

        // creating phones
        for (final String phoneNumber : phoneNumbers) {
            final Phone phone = new Phone();
            phone.setNumber(phoneNumber);
            phone.setEmployee(employee);
            em.persist(phone);
            employee.getPhones().add(phone);
        }

        em.flush(); // making sure a generated id is present

        return employee.getId();
    }
}

いま書いたメソッド create() を呼び出すコードは,以下のようになります:

final Set<Long> projectIds = new HashSet<>();
Collections.addAll(projectIds, project1Id, project2Id);
final Set<String> phoneNumbers = new HashSet<>();
Collections.addAll(phoneNumbers, "000-0000-0001", "000-0000-0002", "000-0000-0003");

final long savedEmployeeId = service.create(
        engineeringDeptId,
        "Jane Doe",
        true,
        projectIds,
        phoneNumbers);

悪くはありません.しかし,もっと複雑なリレーションや省略可能なカラムが多数存在するケースを考えてみてください.それらに対応するメソッドの引数も多くなるのにしたがって,省略可能な引数に対応するためのオーバーロードや null の引数が並ぶメソッド呼び出しも増殖していき,だんだんメンテナンスが大変になっていきます.

このようなケースでは,私が個人的に「JPA Builder パターン」と呼んでいる書き方がおすすめです.以下に示すような非 static のネストされた Builder クラスと,そのインスタンスを生成するためのメソッドを,前述の EmployeeService クラスに対して追加します:

...

public Builder builder(long deptId, String name) {
    return new Builder(deptId, name);
}

public final class Builder { // non-static
    private final long deptId;
    private final String name;
    private boolean temporary;
    private Set<Long> projectIds = new HashSet<>();
    private Set<String> phoneNumbers = new HashSet<>();

    private Builder(final long deptId, final String name) {
        this.deptId = deptId;
        this.name = name;
    }

    public Builder temporary(boolean temporary) {
        this.temporary = temporary;
        return this;
    }

    public Builder projectIds(Long... ids) {
        Collections.addAll(projectIds, ids);
        return this;
    }

    public Builder phoneNumbers(String... numbers) {
        Collections.addAll(phoneNumbers, numbers);
        return this;
    }

    public long build() {
        // In reality, passing "this" instead of actual values (deptId, name, ...) is recommended
        return EmployeeService.this.create(deptId, name, temporary, projectIds, phoneNumbers);
    }
}

これを呼び出すコードは,以下のようになります:

final long savedEmployeeId = service.builder(engineeringDeptId, "Jane Doe")
        .temporary(true)
        .projectIds(project1Id, project2Id)
        .phoneNumbers("000-0000-0001", "000-0000-0002", "000-0000-0003")
        .build();

今回の例のようにリレーションや省略可能なカラムの数がさほど多くない場合,あまりメリットがないように見えるかもしれませんが,現実には,もっと多い数になることは珍しくありません.そのようなケースでは,このパターンを使うことで保守性・可読性を維持・向上させることができます.

このエントリで使用したクラスとテストを含むサンプルの一式は以下にありますので,実際に動かしてみたい方はチェックしてみてください.EclipseLink と Hibernate での動作を確認しています.DB のセットアップなどは必要なく,単に "mvn test" を叩くとインメモリの Apache Derby 上でテストが走ります:

宣伝: 求人のご案内

現在,私の勤めている (株) L is B では,エンジニアを募集しています.主に "direct" という企業向けメッセンジャーの開発と運用を行っている会社です.

残念ながら,今のところ GlassFish や WildFly のようなフルの Java EE コンテナは使われていないのですが,Java EE の構成要素,例えば JPA や JAX-RS などはヘビーに使われています.「Java EE を使って自社サービス開発したい!」という方,ぜひ以下をチェックしてみてください:


JPA Builder Pattern


Posted on Sunday Oct 16, 2016 at 06:07PM in Technology


Thanks to JPA, creating an entity which has tons of fields and complex relations has become much easier than the plain old JDBC era. but there are still some difficulties with it. for example, consider that you have a database schema which is something like following diagram:

829fc6f6 cccb 44c2 816a b7f397e83309

With those entities, let’s say you have to write some code for creating an employee. this would be something like:

public class EmployeeService {

    private final EntityManager em;

    EmployeeService(final EntityManager em) {
        this.em = em;
    }

    public long create(long deptId,
                       String name,
                       boolean temporary,
                       Set<Long> projectIds,
                       Set<String> phoneNumbers) {

        // instantiating and setting attributes of employee
        final Employee employee = new Employee();
        employee.setName(name);
        employee.setTemporary(temporary);
        employee.setProjects(new HashSet<>());
        employee.setPhones(new HashSet<>());

        // making a relation between employee and dept
        final Dept dept = em.find(Dept.class, deptId);
        employee.setDept(dept);
        em.persist(employee);
        dept.getEmployees().add(employee);

        // making relations between employee and projects
        for (final Long projectId : projectIds) {
            final Project project = em.find(Project.class, projectId);
            project.getEmployees().add(employee);
            employee.getProjects().add(project);
        }

        // creating phones
        for (final String phoneNumber : phoneNumbers) {
            final Phone phone = new Phone();
            phone.setNumber(phoneNumber);
            phone.setEmployee(employee);
            em.persist(phone);
            employee.getPhones().add(phone);
        }

        em.flush(); // making sure a generated id is present

        return employee.getId();
    }
}

And you will use the method create() as follows:

final Set<Long> projectIds = new HashSet<>();
Collections.addAll(projectIds, project1Id, project2Id);
final Set<String> phoneNumbers = new HashSet<>();
Collections.addAll(phoneNumbers, "000-0000-0001", "000-0000-0002", "000-0000-0003");

final long savedEmployeeId = service.create(
        engineeringDeptId,
        "Jane Doe",
        true,
        projectIds,
        phoneNumbers);

Not so bad, but think about if there are more complex relations or attributes that may be optional. the arguments of the method will be much longer, and hard to maintain.

In such a case, a pattern which I call "JPA builder pattern" would be nice. you create a non-static nested builder class and a method which creates a builder, into the class EmployeeService, as follows:

...

public Builder builder(long deptId, String name) {
    return new Builder(deptId, name);
}

public final class Builder { // non-static
    private final long deptId;
    private final String name;
    private boolean temporary;
    private Set<Long> projectIds = new HashSet<>();
    private Set<String> phoneNumbers = new HashSet<>();

    private Builder(final long deptId, final String name) {
        this.deptId = deptId;
        this.name = name;
    }

    public Builder temporary(boolean temporary) {
        this.temporary = temporary;
        return this;
    }

    public Builder projectIds(Long... ids) {
        Collections.addAll(projectIds, ids);
        return this;
    }

    public Builder phoneNumbers(String... numbers) {
        Collections.addAll(phoneNumbers, numbers);
        return this;
    }

    public long build() {
        // In reality, passing "this" instead of actual values (deptId, name, ...) is recommended
        return EmployeeService.this.create(deptId, name, temporary, projectIds, phoneNumbers);
    }
}

And you will use the builder as follows:

final long savedEmployeeId = service.builder(engineeringDeptId, "Jane Doe")
        .temporary(true)
        .projectIds(project1Id, project2Id)
        .phoneNumbers("000-0000-0001", "000-0000-0002", "000-0000-0003")
        .build();

It doesn’t make much sense if relations or attributes that may be optional are not that many as this example, but in reality, entities likely to have those much more. in such a case, I believe this pattern makes your code much clean, readable and maintainable.

You can obtain the entire project which contains entities, the service class and executable tests that run with an embedded database, from my GitHub repo.


Jukito integration with JPA and guice-persist


Posted on Sunday Jul 31, 2016 at 11:28AM in Technology


A DI container such as Guice helps you to assemble loosely-coupled classes that easy to write unit tests.

But integration tests, that are necessary thing as well as unit tests, it’s a different story from writing unit tests. writing integration tests involve many cumbersome initialization code of frameworks such as DI container, JPA provider or an application server. they tend to spread across testcases and make testcases messy.

If you use Guice as DI container, Jukito helps you to write integration tests. its official documentation covers some simple usecases, but not mentioned about integration with guice-persist. so in this entry I’ll introduce you how to integrate and begin writing clean testcases without messy boilarplate code with them.

Create an application to be tested

Consider we have a simple JPA entity and a service class which uses it.

An entity class named Employee:

@Entity
public class Employee implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    public Employee(final String name) {
        this.name = name;
    }
...

The service class to be tested named EmployeeService:

public class EmployeeService {

    @Inject
    private EntityManager em;

    @Transactional
    public Long save(final String name) {
        final Employee employee = new Employee(name);
        em.persist(employee);
        em.flush();
        return employee.getId();
    }

    public List<String> findAllNames() {
        return em.createQuery("SELECT e.name FROM Employee e ORDER BY e.name", String.class).getResultList();
    }
}

Create a module for testing

Next, we will create a module for testing (BTW I recommend you to use Module overriding for creating one for testing, based on production one). this would be something like:

// Taken from https://gist.github.com/JWGmeligMeyling/785e459c4cbaab606ed8 , thanks!
public class DatabaseModule extends AbstractModule {

    @Override
    protected void configure() {
        install(new JpaPersistModule("myPU"));
        bind(JPAInitializer.class).asEagerSingleton();
    }

    @Singleton
    private static class JPAInitializer {
        @Inject
        public JPAInitializer(final PersistService service) {
            service.start();
        }
    }
}

Create JpaJukitoRunner

Then, create a special TestRunner which extends JukitoRunner as follows:

public class JpaJukitoRunner extends JukitoRunner {

    public JpaJukitoRunner(final Class<?> klass) throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException {
        super(klass);
    }

    public JpaJukitoRunner(final Class<?> klass, final Injector injector) throws InitializationError, InvocationTargetException, InstantiationException, IllegalAccessException {
        super(klass, injector);
    }

    private UnitOfWork unitOfWork;

    @Override
    protected Object createTest() throws Exception {
        this.unitOfWork = getInjector().getInstance(UnitOfWork.class);
        this.unitOfWork.begin();
        return super.createTest();
    }

    @Override
    public void run(final RunNotifier notifier) {
        notifier.addListener(new RunListener() {

            @Override
            public void testFinished(final Description description) throws Exception {
                // this ensures every tests use distinct entity manager instances
                unitOfWork.end();
            }
        });
        super.run(notifier);
    }
}

This ensures every tests use distinct EntityManager instances for each execution. without this, only one EntityManager instance will be used for all of executions of test cases because it is stored in a ThreadLocal and JUnit uses only one Thread by default for all test executions.

That means that many entities will be kept managed during an execution. consider if you have thousands of test classes in your project - entities will be shared across all of test execution. it will make your EntityManager fat, also your tests may get affected by 1st level cache which got dirty by other test executions.

Create a testcase

Finally, you can write a testcase as follows:

@RunWith(JpaJukitoRunner.class)
@UseModules(DatabaseModule.class)
public class EmployeeServiceTest {

    @Inject
    private EmployeeService sut;
    @Inject
    private EntityManager em;

    @Before
    @Transactional
    public void setUp() throws Exception {
        em.createQuery("DELETE FROM Employee").executeUpdate();
    }

    @Test
    public void saveShouldPersistJohnDoe() throws Exception {
        final String name = "John Doe";

        final long id = sut.save(name);

        final Employee employee = em.find(Employee.class, id);
        assertThat(employee.getName(), is(name));
    }

    @Test
    public void findAllNamesShouldReturnExpectedResult() throws Exception {
        sut.save("Jane Doe");
        sut.save("John Doe");

        final List<String> result = sut.findAllNames();

        assertThat(result.size(), is(2));
    }
}

You can see that there are no any cumbersome initialization code of JPA or database stuff. and note that you can use declarative transaction management by @Transactional, for both the sut class and populating test data into your database.

Cleaning 1st level cache

I have mentioned about bad effect of 1st level cache of EntityManager earlier in this entry, so you may consider that you want to clean 1st level cache. you can do it with em.clear(), or also something like following:

@RunWith(JpaJukitoRunner.class)
@UseModules(DatabaseModule.class)
public class EmployeeServiceTestManagesUOW {

    @Inject
    private Provider<EmployeeService> sut;
    @Inject
    private Provider<EntityManager> em;
    @Inject
    private UnitOfWork unitOfWork;

    @Before
    @Transactional
    public void setUp() throws Exception {
        em.get().createQuery("DELETE FROM Employee").executeUpdate();
    }

    @Test
    public void saveShouldPersistJohnDoe() throws Exception {
        final String name = "John Doe";
        newEntityManager();

        final long id = sut.get().save(name);

        newEntityManager();
        final Employee employee = em.get().find(Employee.class, id);
        assertThat(employee.getName(), is(name));
    }

    private void newEntityManager() {
        unitOfWork.end();
        unitOfWork.begin();
    }
}

In this test, there are three distinct EntityManagers involved in a test execution. the one in setUp(), another one in invocation of sut#save() and finally one for em#find() which is used for assertion.

But in my opinion, this is an overkill and using one shared EntityManager for one test execution would be sufficient. if it didn’t work well, something may wrong with your usage of JPA.

Conclusion

We have seen how testcases which involve JPA and guice-persist could be written cleanly with Jukito. it enables us to eliminate cumbersome boilarplate code for managing and invoking Injector, JPA initialization and manual transaction management. now our testcases look pretty clean.

Executable testcases and the example project can be obtained from my GitHub repository.

References


Managing multiple JPA persistence units with guice-persist


Posted on Sunday Jun 19, 2016 at 06:15PM in Technology


Guice has an extension named guice-persist which aim for providing integration between Guice and a data persistence mechanism. it gives declarative transaction management functionality with the annotation @com.google.inject.persist.Transactional which works with a standalone environment or plain servlet containers such as Tomcat or Jetty.

guice-persist supports JPA and it’s simple to use with only one persistence unit, but to use it with multiple persistence units, it requires some tricks.

The official Guice wiki has only some brief description and I can’t find any complete example to implement it in an actual application. so, in this entry I’ll give you a complete example about how to write a module which manages multiple persistence units.

Module hierarchy

To manage multiple PUs in a module, you should create PrivateModule subclasses of the same number of your persistence units.

Let’s say we have two persistence units that one is named masterPU and another one named slavePU. For example, we have the following persistence.xml in an application:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="masterPU" transaction-type="RESOURCE_LOCAL">
...
    </persistence-unit>
    <persistence-unit name="slavePU" transaction-type="RESOURCE_LOCAL">
...
    </persistence-unit>
</persistence>

In this case, we are going to create and assemble classes as the following diagram:

1788876a 6b06 4be0 a5d1 4cc3c2897b23

MasterPu and SlavePu are qualifier annotations that used for distinguish multiple bindings of JPA classes.

Writing modules

So, how do you write those modules? I’ll show you some important parts of them.

Qualifier annotations

First you need to create the two qualifier annotations something like this:

import static java.lang.annotation.ElementType.*;

@javax.inject.Qualifier
@java.lang.annotation.Target({FIELD, PARAMETER, METHOD})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface MasterPu {
}

Don’t forget about SlavePu as well.

JpaPersistPrivateModule

Now here’s the most important part - this class installs JpaPersistModule and rebinds and exposes JPA class bindings:

public class JpaPersistPrivateModule extends PrivateModule {
    protected final String persistenceUnitName;
    protected final Properties props;
    protected final Class<? extends Annotation> qualifier;

    public JpaPersistPrivateModule(final String persistenceUnitName, final Properties props, final Class<? extends Annotation> qualifier) {
        this.persistenceUnitName = persistenceUnitName;
        this.props = props;
        this.qualifier = qualifier;
    }

    public JpaPersistPrivateModule(final String persistenceUnitName, final Class<? extends Annotation> qualifier) {
        this(persistenceUnitName, new Properties(), qualifier);
    }

    @Override
    protected void configure() {
        install(new JpaPersistModule(persistenceUnitName).properties(props));
        rebind(qualifier, EntityManagerFactory.class, EntityManager.class, PersistService.class, UnitOfWork.class);
        doConfigure();
    }

    private void rebind(Class<? extends Annotation> qualifier, Class<?>... classes) {
        for (Class<?> clazz : classes) {
            rebind(qualifier, clazz);
        }
    }

    private <T> void rebind(Class<? extends Annotation> qualifier, Class<T> clazz) {
        bind(clazz).annotatedWith(qualifier).toProvider(binder().getProvider(clazz));
        expose(clazz).annotatedWith(qualifier);
    }

    /**
     * bind your interfaces and classes as well as concrete ones that use JPA classes explicitly
     */
    protected void doConfigure() {
        // write your bindings in your subclasses
        // bindConcreteClassWithQualifier(MyTableService.class);
        // ...
    }

    /**
     * binds and exposes a concrete class with an annotation
     */
    protected <T> void bindConcreteClassWithQualifier(Class<T> clazz) {
        bind(clazz).annotatedWith(qualifier).to(clazz);
        expose(clazz).annotatedWith(qualifier);
    }

    /**
     * binds and exposes a concrete class without any annotation
     */
    protected void bindConcreteClass(Class<?> clazz) {
        bind(clazz);
        expose(clazz);
    }
}

First, this class installs JpaPersistModule and it creates bindings of JPA classes without any annotation but those bindings will not be exposed globally because we are in a PrivateModule. then, this class rebinds them with a qualifier annotation and exposes them with qualifier annotation. eventually, bindings of the four JPA classes will be created with a qualifier annotation.

MyModule, MasterPuModule and SlavePuModule

public class MyModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new MasterPuModule());
        install(new SlavePuModule());
    }

    private static class MasterPuModule extends JpaPersistPrivateModule {
        public MasterPuModule() {
            super("masterPU", MasterPu.class);
        }

        @Override
        protected void doConfigure() {
            bindConcreteClassWithQualifier(MyTableService.class);
        }
    }

    private static class SlavePuModule extends JpaPersistPrivateModule {
        public SlavePuModule() {
            super("slavePU", SlavePu.class);
        }

        @Override
        protected void doConfigure() {
            bindConcreteClassWithQualifier(MyTableService.class);
        }
    }
}

This class installs two JpaPersistPrivateModule subclasses for persistence units and binds a service class named MyTableService which requires injection of EntityManager. this module creates two distinct annotated bindings for the class.

Note that if you need declarative transaction management by @Transactional for your service classes, you should create bindings of them inside doConfigure(). for example, if you creates such bindings in MyModule#configure(), declarative transactions won’t work.

How about PersistFilter?

If you need PersistFilter for those two modules, you need to create a binding for each modules inside doConfigure() as follows:

Key<PersistFilter> key = Key.get(PersistFilter.class, qualifier);
bind(key).to(PersistFilter.class);
expose(key);

Then, install all of modules inside your subclass of ServletModule. after that, create filter mappings inside configureServlets() as follows:

filter("/*").through(Key.get(PersistFilter.class, MasterPu.class));
filter("/*").through(Key.get(PersistFilter.class, SlavePu.class));

Conclusion

We have seen an example of a Guice module that manages two persistence units with guice-persist. check my GitHub repository for the complete example project and testcases.


Using JPQL IN clause with composite key


Posted on Sunday Oct 25, 2015 at 08:16PM in JPA


Assume we have an entity named Employee:

@Entity
public class Employee implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    @Embedded
    private EmployeeName employeeName;

    // accessor omitted

And EmployeeName:

@Embeddable
public class EmployeeName implements Serializable {
    private String firstName;
    private String lastName;

    // accessor omitted

Using preceding entity, We want to execute following JPQL:

SELECT e FROM Employee e WHERE e.employeeName IN :employeeNames

Will it work? It works for Hibernate 4.3.11.Final but unfortunately not for EclipseLink 2.6.1.

Hibernate generates following SQL for the JPQL and the parameter of a List contains two elements:

Hibernate: select employee0_.id as id1_0_, employee0_.firstName as firstNam2_0_, employee0_.lastName as lastName3_0_ from Employee employee0_ where employee0_.firstName=? and employee0_.lastName=? or employee0_.firstName=? and employee0_.lastName=?
[Employee{id=1, employeeName=EmployeeName{firstName='Scott', lastName='Vogel'}}, Employee{id=2, employeeName=EmployeeName{firstName='Nick', lastName='Jett'}}]

EclipseLink failed to generate correct SQL for the JPQL. In such case, you need to create a JPQL by hand or Criteria API that uses each column separately (lastName and firstName). EclipseLink produces following Exception:

Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLDataException: An attempt was made to get a data value of type 'BIGINT' from a data value of type 'entity.EmployeeName'.
Error Code: 20000
Call: SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN (?,?))
	bind => [EmployeeName{firstName='Scott', lastName='Vogel'}, EmployeeName{firstName='Nick', lastName='Jett'}]
Query: ReadAllQuery(referenceClass=Employee sql="SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN ?)")
	at org.eclipse.persistence.internal.jpa.QueryImpl.getDetailedException(QueryImpl.java:382)
	at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:260)
	at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:473)
	at main.Main.main(Main.java:45)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLDataException: An attempt was made to get a data value of type 'BIGINT' from a data value of type 'entity.EmployeeName'.
Error Code: 20000
Call: SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN (?,?))
	bind => [EmployeeName{firstName='Scott', lastName='Vogel'}, EmployeeName{firstName='Nick', lastName='Jett'}]
Query: ReadAllQuery(referenceClass=Employee sql="SELECT ID, FIRSTNAME, LASTNAME FROM EMPLOYEE WHERE (ID IN ?)")
	at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:684)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:560)
	at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2055)
	at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570)
	at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:258)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694)
	at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2740)
	at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2693)
	at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:559)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1175)
	at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1134)
	at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:460)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1222)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
	at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
	... 7 more

Complete source code that has been used in the test can be obtained from https://github.com/lbtc-xxx/jpa-composite-in