JPA entity classes are not discovered automatically with Gradle

I’m new to Gradle. I’m trying to run some tests but they fail with messages showing that the entity classes are not mapped. When I explicitly map the classes in persistence.xml everything works fine. I did some research and found that adding theses lines to the build script would solve the problem:

sourceSets.main.output.resourcesDir = sourceSets.main.output.classesDir
sourceSets.test.output.resourcesDir = sourceSets.test.output.classesDir

but it simply didn’t work for me. I still get the errors if I don’t specify the classes in the deployment descriptor.

What could be wrong?

Cross-posted: java - JPA entity classes are not discovered automatically with Gradle - Stack Overflow

Hi, Marcos.

Can I see your persistence.xml and project structure( and build.gradle)?

And did you test it in Java SE environment, or in Java EE container?

I’m testing in Java SE.

persistence.xml:

<?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="bd">
		<class>br.desenvolvimento.teste.modelo.Cliente</class>
		<class>br.desenvolvimento.teste.modelo.Banco</class>
		<class>br.desenvolvimento.teste.modelo.AgenciaBancaria</class>
		<class>br.desenvolvimento.teste.modelo.ContaBancaria</class>
		<class>br.desenvolvimento.teste.modelo.Filho</class>
		<class>br.desenvolvimento.teste.modelo.Projeto</class>
		<class>br.desenvolvimento.teste.modelo.Telefone</class>
		
		<properties>
			<property name="hibernate.show_sql" value="false" />
		</properties>
	</persistence-unit>
</persistence>

My project structure:

C:\desenvolvimento\teste\teste\.classpath
C:\desenvolvimento\teste\teste\.gradle
C:\desenvolvimento\teste\teste\.project
C:\desenvolvimento\teste\teste\.settings
C:\desenvolvimento\teste\teste\build.gradle
C:\desenvolvimento\teste\teste\cfg.properties
C:\desenvolvimento\teste\teste\gradle
C:\desenvolvimento\teste\teste\gradlew
C:\desenvolvimento\teste\teste\gradlew.bat
C:\desenvolvimento\teste\teste\src
C:\desenvolvimento\teste\teste\.settings\gradle.prefs
C:\desenvolvimento\teste\teste\gradle\wrapper
C:\desenvolvimento\teste\teste\gradle\wrapper\gradle-wrapper.jar
C:\desenvolvimento\teste\teste\gradle\wrapper\gradle-wrapper.properties
C:\desenvolvimento\teste\teste\src\main
C:\desenvolvimento\teste\teste\src\test
C:\desenvolvimento\teste\teste\src\main\java
C:\desenvolvimento\teste\teste\src\main\resources
C:\desenvolvimento\teste\teste\src\main\java\br
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\AgenciaBancaria.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Banco.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Cliente.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\CodigoAgenciaBancaria.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\CodigoCliente.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\CodigoContaBancaria.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\CodigoFilho.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\CodigoTelefone.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\ContaBancaria.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Endereco.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Filho.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Projeto.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Sexo.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\Telefone.java
C:\desenvolvimento\teste\teste\src\main\java\br\desenvolvimento\teste\modelo\TipoSangue.java
C:\desenvolvimento\teste\teste\src\main\resources\META-INF
C:\desenvolvimento\teste\teste\src\main\resources\META-INF\img
C:\desenvolvimento\teste\teste\src\main\resources\META-INF\MANIFEST.MF
C:\desenvolvimento\teste\teste\src\main\resources\META-INF\menu.xml
C:\desenvolvimento\teste\teste\src\main\resources\META-INF\persistence.xml
C:\desenvolvimento\teste\teste\src\main\resources\META-INF\img\icone.gif
C:\desenvolvimento\teste\teste\src\main\resources\META-INF\img\localizar.gif
C:\desenvolvimento\teste\teste\src\test\java
C:\desenvolvimento\teste\teste\src\test\resources
C:\desenvolvimento\teste\teste\src\test\java\br
C:\desenvolvimento\teste\teste\src\test\java\br\desenvolvimento
C:\desenvolvimento\teste\teste\src\test\java\br\desenvolvimento\teste
C:\desenvolvimento\teste\teste\src\test\java\br\desenvolvimento\teste\teste
C:\desenvolvimento\teste\teste\src\test\java\br\desenvolvimento\teste\teste\TesteFormatacao.java
C:\desenvolvimento\teste\teste\src\test\resources\META-INF
C:\desenvolvimento\teste\teste\src\test\resources\META-INF\persistence.xml

I tried to upload an image of my project structure because it’s better to view, but new users like me are forbidden

In Java SE environment with Hibernate, class elements is needed in persistence-unit element.

In JPA2.1 Specification(JSR338 8.2.1.6.4), it is described that

A list of all named managed persistence classes must be specified in Java SE environments to insure
portability. Portable Java SE applications should not rely on the other mechanisms described here to
specify the managed persistence classes of a persistence unit.

If you do not want to list classes, there are several ways to generate persistence.xml.

  • generate persistence.xml with Annotation Processor.
  • generate persistence.xml with Gradle custom task(, but it’s not available on executing test in IDE).
  • let IDE to list classes

I’ve been programming in Java SE using JPA for more than six years and I can assure you that, before using Gradle, I have never had the need to explicitly specify the entity classes that reside in the same jar where persistence.xml reside for my application to work. And I don’t even have to list them if I’m running in Java EE. Sometimes I only have to list the classes if they are located in another jar, which is not the case here.

It would be very sad from the JPA specification if I had to declare all my classes in the deployment descriptor that lives in the same jar.

Again, before using Gradle (at least for testing), I didn’t need to declared the mapped classes in persistence.xml for the application to work. They were discovered automatically.

I’ve debugged this to root cause. When running unit tests, Gradle puts build/resources/main on the classpath which contains META-INF/persistence.xml. Hibernate (at least version 3.6.7) loads persistence.xml using the context class loader and extracts the URL of persistence.xml. The URL looks like /…/build/resources/main/META-INF/persistence.xml. From this URL, Hibernate then extracts the jarURL as /…/build/resources/main/. It is this URL that is used to scan for classes annotated with @Entity for which there are none since the classes are in build/classes. When you set:

sourceSets.main.output.resourcesDir = sourceSets.main.output.classesDir

Gradle puts the META-INF/persistence.xml in build/classes. Now, when Hibernate runs, it finds persistence.xml in /…/build/classes/main/META-INF/persistence.xml which then turns into a jarURL of /…/build/classes/main which does contain your classes annotated with @Entity and everything now works.