admin-persistence

Provides CRUD utilities for CDI, JPA, JSF and PrimeFaces based applications.

License

License

GroupId

GroupId

com.github.adminfaces
ArtifactId

ArtifactId

admin-persistence
Last Version

Last Version

1.2.0
Release Date

Release Date

Type

Type

jar
Description

Description

admin-persistence
Provides CRUD utilities for CDI, JPA, JSF and PrimeFaces based applications.
Project URL

Project URL

https://github.com/adminfaces/admin-persistence
Source Code Management

Source Code Management

https://github.com/adminfaces/admin-persistence.git

Download admin-persistence

How to add to project

<!-- https://jarcasting.com/artifacts/com.github.adminfaces/admin-persistence/ -->
<dependency>
    <groupId>com.github.adminfaces</groupId>
    <artifactId>admin-persistence</artifactId>
    <version>1.2.0</version>
</dependency>
// https://jarcasting.com/artifacts/com.github.adminfaces/admin-persistence/
implementation 'com.github.adminfaces:admin-persistence:1.2.0'
// https://jarcasting.com/artifacts/com.github.adminfaces/admin-persistence/
implementation ("com.github.adminfaces:admin-persistence:1.2.0")
'com.github.adminfaces:admin-persistence:jar:1.2.0'
<dependency org="com.github.adminfaces" name="admin-persistence" rev="1.2.0">
  <artifact name="admin-persistence" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.github.adminfaces', module='admin-persistence', version='1.2.0')
)
libraryDependencies += "com.github.adminfaces" % "admin-persistence" % "1.2.0"
[com.github.adminfaces/admin-persistence "1.2.0"]

Dependencies

compile (5)

Group / Artifact Type Version
org.primefaces : primefaces jar 8.0
org.apache.deltaspike.core : deltaspike-core-impl jar 1.8.2
org.apache.deltaspike.core : deltaspike-core-api jar 1.8.2
org.apache.deltaspike.modules : deltaspike-data-module-api jar 1.8.2
org.apache.deltaspike.modules : deltaspike-data-module-impl jar 1.8.2

provided (2)

Group / Artifact Type Version
javax : javaee-api jar 7.0
org.hibernate : hibernate-core jar 4.2.8.Final

test (8)

Group / Artifact Type Version
junit : junit jar 4.12
org.hsqldb : hsqldb jar 2.3.3
org.assertj : assertj-core jar 3.6.2
com.github.database-rider : rider-cdi jar 1.2.1
org.apache.deltaspike.modules : deltaspike-test-control-module-impl jar 1.8.2
org.apache.deltaspike.cdictrl : deltaspike-cdictrl-owb jar 1.8.2
org.apache.openwebbeans : openwebbeans-impl jar 1.6.2
org.hibernate : hibernate-entitymanager jar 4.2.8.Final

Project Modules

There are no modules declared in this project.

Admin Persistence

1. Prerequisites

This module depends on JSF, CDI and JPA and was tested with respective implementations and versions:

JSF

CDI

JPA

Mojarra 2.2

Weld 2.3

Hibernate 5.0

Mojarra 2.2

Weld 2.2

Hibernate 4.3

MyFaces 2.1

OpenWebBeans 1.7.4

Eclipselink 2.6

2. Usage

Following are the steps you need to follow in order to use Admin Persistence:

  1. Classpath

    First include it in your classpath:

    <dependency>
        <groupId>com.github.adminfaces</groupId>
        <artifactId>admin-persistence</artifactId>
        <version>1.0.7</version>
    </dependency>

    Admin persistence will bring the following transitive dependencies:

    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>7.0</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.deltaspike.core</groupId>
        <artifactId>deltaspike-core-impl</artifactId>
        <version>1.8.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.deltaspike.core</groupId>
        <artifactId>deltaspike-core-api</artifactId>
        <version>1.8.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-data-module-api</artifactId>
        <version>1.8.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.deltaspike.modules</groupId>
        <artifactId>deltaspike-data-module-impl</artifactId>
        <version>1.8.2</version>
    </dependency>

    Of cource you can override them in your pom.xml as needed.

  2. JPA Metamodel

    As Admin Persistence uses DeltaSpike typesafe criteria you’ll need to generate JPA metamodel. There are various ways to do that, here is a maven plugin example:

    <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>apt-maven-plugin</artifactId>
        <version>1.1.3</version>
        <executions>
            <execution>
                <id>metamodel</id>
                <goals>
                    <goal>process</goal>
                </goals>
                <configuration>
                    <outputDirectory>target/generated-sources/metamodel</outputDirectory>
                    <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
                </configuration>
            </execution>
        </executions>
        <dependencies>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-jpamodelgen</artifactId>
                <version>4.3.8.Final</version>
            </dependency>
        </dependencies>
    </plugin>
    💡
    See this tutorial for configuring it on your IDE.
  3. Entity Manager

    Admin persistence needs an exposed entity manager as CDI Bean, you can do that by using a CDI producer:

    @ApplicationScoped
    public class EntityManagerProducer {
    
        @PersistenceContext
        EntityManager em;
    
        @Produces
        public EntityManager produce() {
            return em;
        }
    }
  4. Persistence Entity

    Every JPA entity must be typed as a PersistenceEntity, it is an interface with only a method, getId():

    import com.github.adminfaces.persistence.model.PersistenceEntity;
    
    @Entity
    @Table(name = "car")
    public class Car implements PersistenceEntity {
    
    @Override
    public Integer getId() {
            return id;
        }
    
    }
    💡
    You can extend BaseEntity to gain equals(),hashCode() and toString().
  5. Service layer

    Now to create a service which will hold your business logic you need to extend CrudService:

    @Stateless
    public class CarService extends CrudService<Car, Integer>  {
    
    }
    💡
    Full source code for CarService can be found here.
    ℹ️
    For some examples of CrudService usage see integration tests here.
  6. Controller

    Finally on the controller layer (JSF managed beans) you need to extend CrudMB which will enable CRUD support for your JSF pages:

    @Named
    @ViewScoped
    public class CarListMB extends CrudMB<Car> implements Serializable {
    
        @Inject
        CarService carService;
    
        @Inject
        @Service
        CrudService<Car, Integer> crudService; //generic injection
    
        @Inject
        public void initService() {
           setCrudService(carService); (1)
        }
    
    }
    1. Needed by CrudMB otherwise it will throw an exception asking for CrudService initialization.

    💡

    You can use @BeanService annotation to provide CrudService:

    @Named
    @ViewScoped
    @BeanService(CarService.class)//use annotation instead of setter injection
    public class CarListMB extends CrudMB<Car> implements Serializable {
    
    }
    💡
    Full source code for CarListMB can be found here.

3. Pagination

Real pagination involves lots of boilerplate code, in admin-persistence it is a matter of using a Primefaces lazy datatable and bind it to the CrudMB list variable:

xhtml page
 <p:dataTable widgetVar="carsTable" var="c" value="#{carListMB.list}"
       rows="5" rowKey="#{c.id}"
       lazy="true" paginator="true"
      <!-- other attributes -->
💡
Full source code for this xhtml page can be found here.

4. Pagination filtering

For filtering on the lazy datatable you just need to override configRestrictions method in the managed bean’s service (the service we set in CarListMB) and add your restrictions based on a filter:

CarService
protected Criteria<Car, Car> configRestrictions(Filter<Car> filter) {

        Criteria<Car, Car> criteria = criteria();

        //create restrictions based on parameters map
        if (filter.hasParam("id")) {
            criteria.eq(Car_.id, filter.getIntParam("id"));
        }

        if (filter.hasParam("minPrice") && filter.hasParam("maxPrice")) {
            criteria.between(Car_.price, filter.getDoubleParam("minPrice"), filter.getDoubleParam("maxPrice"));
        } else if (filter.hasParam("minPrice")) {
            criteria.gtOrEq(Car_.price, filter.getDoubleParam("minPrice"));
        } else if (filter.hasParam("maxPrice")) {
            criteria.ltOrEq(Car_.price, filter.getDoubleParam("maxPrice"));
        }

        //create restrictions based on filter entity
        if (has(filter.getEntity())) {
            Car filterEntity = filter.getEntity();
            if (has(filterEntity.getModel())) {
                criteria.likeIgnoreCase(Car_.model, "%"+filterEntity.getModel());
            }

            if (has(filterEntity.getPrice())) {
                criteria.eq(Car_.price, filterEntity.getPrice());
            }

            if (has(filterEntity.getName())) {
                criteria.likeIgnoreCase(Car_.name, "%"+filterEntity.getName());
            }
        }
        return criteria;
    }
ℹ️

filter.params is a hashmap used to add arbitrary parameters and filter.entity is for entity specific ones, see search dialog which populates those attributes:

<div class="ui-g-12">
    <p:outputLabel for="model" value="#{msg['label.model']}"/>
</div>
<div class="ui-g-12">
    <p:selectOneMenu id="model" value="#{carListMB.filter.entity.model}">
        <f:selectItem itemLabel="Chose a model" itemValue=""/>
        <f:selectItems value="#{models}" var="m" itemLabel="#{m}"
            itemValue="#{m}"/>
    </p:selectOneMenu>
</div>
<div class="ui-g-12">
    <p:outputLabel for="name" value="#{msg['label.name']}"/>
</div>
<div class="ui-g-12">
    <p:inputText id="name" value="#{carListMB.filter.entity.name}"/>
</div>
<div class="ui-g-6 ui-sm-12 ui-g-nopad">
    <div class="ui-g-12">
        <p:outputLabel for="min" value="#{msg['label.minPrice']}"/>
    </div>
    <div class="ui-g-12">
        <p:inputNumber id="min" value="#{carListMB.filter.params.minPrice}"/>
    </div>
</div>
<div class="ui-g-6 ui-sm-12 ui-g-nopad">
    <div class="ui-g-12">
        <p:outputLabel for="max" value="#{msg['label.maxPrice']}"/>
    </div>
    <div class="ui-g-12">
        <p:inputNumber id="max" value="#{carListMB.filter.params.maxPrice}"/>
    </div>
</div>
Any datatable update (ajax or not) will trigger the configRestrictions.
ℹ️
Besides filtering the filter helper class also holds pagination and sort information.
⚠️

By default filters are saved on Session so when user goes to another page (e.g a detail) and comes back to list the tables keeps it’s previous filters.

You can change this behavior by overriding keepFiltersInSession method on your Bean:

CarListMB
    @Override
    public boolean keepFiltersInSession() {
        return false;
    }

5. Sample application

For an example project using Admin Persistence see admin-starter-persistence.

💡
For a composite-key demo see this branch of admin-starter.

6. Snapshots

Snapshots are published to maven central on each commit, to use it just declare the repository below on your pom.xml:

<repositories>
    <repository>
        <snapshots/>
        <id>snapshots</id>
        <name>libs-snapshot</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>
com.github.adminfaces

Versions

Version
1.2.0
1.1.0
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-RC12
1.0.0-RC11
1.0.0-RC10
1.0.0-RC9
1.0.0-RC8
1.0.0-RC7
1.0.0-RC6
1.0.0-RC5
1.0.0-RC4
1.0.0-RC3
1.0.0-RC2
1.0.0-RC1