Utility library for OmniFaces + PrimeFaces combined.
This project basically combines best of OmniFaces and PrimeFaces with help of OmniPersistence, an utility library for JPA. This project should make it a breeze to create semi-dynamic lazy-loaded, searchable, sortable and filterable <p:dataTable> based on a JPA model and a generic entity service.
pom.xml
<dependencies>
<!-- Target Java EE server. -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version><!-- Minimum supported version is 7.0 -->
<scope>provided</scope>
</dependency>
<!-- Runtime dependencies. -->
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.13.3</version><!-- Minimum supported version is 3.0 -->
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>10.0.0</version><!-- Minimum supported version is 10.0.0 -->
</dependency>
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>optimusfaces</artifactId>
<version>0.15</version>
</dependency>
</dependencies>Minumum supported Java / OmniFaces / PrimeFaces versions
- OptimusFaces 0.1 - 0.14: Java 11 / OmniFaces 2.2 / PrimeFaces 7.0
- OptimusFaces 0.15+: Java 11 / OmniFaces 3.0 / PrimeFaces 10.0.0
- OptimusFaces 0.14-J1+: Java 11 / OmniFaces 4.0 / PrimeFaces 10.0.0:jakarta
- OptimusFaces 0.17-J1+: Java 17 / OmniFaces 4.0 / PrimeFaces 13.0.0:jakarta
First create your entity service extending org.omnifaces.omnipersistence.service.BaseEntityService. You don't necessarily need to add new methods, just extending it is sufficient. It's useful for other generic things too.
@Stateless
public class YourEntityService extends BaseEntityService<Long, YourEntity> {
// ...
}And make sure YourEntity extends org.omnifaces.omnipersistence.model.BaseEntity or one of its subclasses GeneratedIdEntity, TimestampedEntity, TimestampedBaseEntity, VersionedEntity or VersionedBaseEntity.
@Entity
public class YourEntity extends BaseEntity<Long> {
@Id @GeneratedValue(strategy=IDENTITY)
private Long id;
private Instant created;
private String name;
private Type type;
private boolean deleted;
// ...
}Then create a org.omnifaces.optimusfaces.model.PagedDataModel in your backing bean as below.
@Named
@ViewScoped
public class YourBackingBean implements Serializable {
private PagedDataModel<YourEntity> model;
@Inject
private YourEntityService service;
@PostConstruct
public void init() {
model = PagedDataModel.lazy(service).build();
}
public PagedDataModel<YourEntity> getModel() {
return model;
}
}Finally use <op:dataTable> to have a semi-dynamic lazy-loaded, pageable, sortable and filterable
<p:dataTable> without much hassle.
<... xmlns:op="http://omnifaces.org/optimusfaces">
<h:form id="yourEntitiesForm">
<op:dataTable id="yourEntitiesTable" value="#{yourBackingBean.model}">
<op:column field="id" />
<op:column field="created" />
<op:column field="name" />
<op:column field="type" />
<op:column field="deleted" />
</op:dataTable>
</h:form>The field attribute of <op:column> represents the entity property path. This will
in turn be used in id, field, headerText and filterBy attributes
of <p:column>.
Here's how it looks like with default PrimeFaces UI and all. This example uses exactly the above Java and XHTML code with a Person entity with Long id, String email, Gender gender and LocalDate dateOfBirth fields.
- EclipseLink refuses to perform a
JOINwith Criteria API when setFirstResult/setMaxResults is used. This returns a cartesian product. This has been workarounded, but this removes the ability to perform sorting on a column referenced by a join (@OneToManyand@ElementCollection). You should set such columns as<op:column ... sortable="false">. Another consequence is that you cannot search with a multi-valued criteria in a field referenced by a@OneToManyrelationship. You should consider using a DTO instead. - OpenJPA adds internally a second
JOINwhen sorting a column referenced by a join (@OneToManyand@ElementCollection). This has as consequence that the sorting is performed on a different join than the one referenced inGROUP BYand will thus be off from what's presented. You should for now set such columns as<op:column ... sortable="false">or consider using a DTO instead. - OpenJPA does not correctly apply setFirstResult/setMaxResults when an
@OneToManyrelationship is involved in the query. It will basically apply it on the results of the@OneToManyrelationship instead of on the query root, causing the page to contain fewer records than expected. There is no clear solution/workaround for that yet.
The integration tests currently run on following environments:
- WildFly 26.1.1 with Mojarra 2.3.17 and Hibernate 5.3.24
- WildFly 26.1.1 with Mojarra 2.3.17 and EclipseLink 2.7.10
- Payara 5.2022.2 with Mojarra 2.3.14 and Hibernate 5.4.33
- Payara 5.2022.2 with Mojarra 2.3.14 and EclipseLink 2.7.9
- TomEE 8.0.11 with MyFaces 2.3.9 and OpenJPA 3.2.2
Each environment will run the IT on following databases:
- H2 1.4.200 (embedded database)
- MySQL latest 8.x (provided by GitHub Actions) with JDBC driver 8.0.29
- PostgreSQL latest 12.x (provided by GitHub Actions) with JDBC driver 42.3.5
Effectively, there are thus 15 full test runs of each 31 test cases on 19 XHTML files.
