Maven plugin that scans a package of JPA entity classes and generates the corresponding *Service interface, *ServiceImpl class, and *Repository interface for each entity. Run it once to bootstrap the service layer — the generated files land in src/main/java and are then yours to modify.
- Overview
- What gets generated
- Plugin configuration
- Parameters reference
- Running the plugin
- Generated file structure
- After generation
The plugin runs in the generate-sources Maven lifecycle phase. It reads the source files in the entity package (using AST parsing — no compilation required), extracts the entity class name and primary-key type, and writes three Java source files per entity using FreeMarker templates.
Because the output goes to src/main/java (or a configured directory), the files are committed to version control and edited freely. The plugin will not overwrite files that already exist — subsequent builds are safe.
For each entity class found in persistencePackage, the plugin produces:
@Repository
public interface ProductRepository extends BaseJpaRepository<Product, Long> {
}BaseJpaRepository<T, ID> extends JpaRepository<T, ID> and is the standard repository type used by the framework.
public interface ProductService extends JpaService<Product, Long> {
}Extend this interface to add custom service methods beyond the standard CRUD / filter-based ones.
@Service
@Transactional
@QueryBuilder
public class ProductServiceImpl extends JpaServiceImpl<Product, Long>
implements ProductService {
@Autowired
private ProductRepository productRepository;
@PersistenceContext
private EntityManager entityManager;
@Override
protected JpaRepository<Product, Long> getJpaRepository() {
return this.productRepository;
}
@Override
protected EntityManager getEntityManager() {
return this.entityManager;
}
}The @QueryBuilder annotation is placed with no attributes — add conditions, joins, and order definitions to it after the file is generated (see processor-jpa-service documentation).
Add the plugin to the <build><plugins> section of your pom.xml:
<plugin>
<groupId>com.bld.commons</groupId>
<artifactId>jpa-service-plugin-generator</artifactId>
<version>3.0.18</version>
<executions>
<execution>
<goals>
<goal>jpa-service-generator</goal>
</goals>
</execution>
</executions>
<configuration>
<persistencePackage>com.example.domain</persistencePackage>
<servicePackage>com.example.service</servicePackage>
<basePackage>com.example</basePackage>
<!-- optional -->
<repositoryPackage>com.example.repository</repositoryPackage>
<outputDirectory>src_main_java</outputDirectory>
</configuration>
</plugin>| Parameter | Required | Default | Description |
|---|---|---|---|
persistencePackage |
Yes | — | Fully qualified package containing the JPA entity classes to scan |
servicePackage |
Yes | — | Target package where *Service and *ServiceImpl files are written |
basePackage |
Yes | — | Root package of your application (used for output path resolution) |
repositoryPackage |
No | Derived from entity package | Target package where *Repository files are written. Defaults to the entity class package with the class name segment removed |
outputDirectory |
No | src_main_java |
Output directory type. src_main_java writes directly into src/main/java |
resourceTemplateDirectory |
No | /template |
Location of the FreeMarker templates inside the plugin JAR |
If repositoryPackage is not set, the repository is written into the same package as the entity. For example, if an entity is com.example.domain.Product, the repository will be com.example.domain.ProductRepository.
To keep repositories in a separate package, set repositoryPackage explicitly:
<repositoryPackage>com.example.repository</repositoryPackage>The plugin is bound to the generate-sources phase and runs automatically during a normal build. To trigger it in isolation:
mvn com.bld.commons:jpa-service-plugin-generator:jpa-service-generatorOr, if the plugin is in your POM under <pluginManagement>:
mvn generate-sourcesFiles are written only if they do not already exist. Add the output directories to .gitignore if you prefer to regenerate them, or commit them to version control to track your customisations.
Given persistencePackage = com.example.domain, servicePackage = com.example.service, repositoryPackage = com.example.repository, and entities Product, Order, Customer:
src/main/java/
com/example/
domain/
Product.java ← your entity (untouched)
Order.java
Customer.java
repository/
ProductRepository.java ← generated
OrderRepository.java ← generated
CustomerRepository.java ← generated
service/
ProductService.java ← generated
ProductServiceImpl.java ← generated
OrderService.java ← generated
OrderServiceImpl.java ← generated
CustomerService.java ← generated
CustomerServiceImpl.java ← generated
Once the files are generated:
-
Add
@QueryBuilderattributes to each*ServiceImplto define conditions, joins, and sort keys. The annotation processor (processor-jpa-service) reads these to generate the*QueryJpqlImplclass. -
Add custom methods to the
*Serviceinterface and implement them in*ServiceImplas needed. -
Configure the annotation processor in the Maven compiler plugin so the
@QueryBuilderannotation on each*ServiceImplis picked up at compile time:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.bld.commons</groupId>
<artifactId>processor-jpa-service</artifactId>
<version>3.0.18</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>See the processor-jpa-service documentation for the full @QueryBuilder attribute reference.