DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Controlling Access to Google BigQuery Data
  • Enterprise RIA With Spring 3, Flex 4 and GraniteDS
  • Data Security Considerations in Cloud Data Warehouses
  • How To Build Web Service Using Spring Boot 2.x

Trending

  • Kubeflow: Driving Scalable and Intelligent Machine Learning Systems
  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  • Streamlining Event Data in Event-Driven Ansible
  • AI Meets Vector Databases: Redefining Data Retrieval in the Age of Intelligence
  1. DZone
  2. Data Engineering
  3. Data
  4. The Data Access Layer in Jmix: JPA on Steroids

The Data Access Layer in Jmix: JPA on Steroids

With Jmix JPA metadata, you get advanced security, soft delete and generic REST and GraphQL out-of-the-box almost without coding.

By 
Andrey Belyaev user avatar
Andrey Belyaev
DZone Core CORE ·
Updated Mar. 23, 21 · Review
Likes (17)
Comment
Save
Tweet
Share
5.9K Views

Join the DZone community and get the full member experience.

Join For Free

JPA with Jmix

Introduction

The data model is one of the cornerstones of any enterprise application. When you start planning the model, you should not only take into account business data requirements but also answer some additional questions that may affect your application design. For example: do you need row-based security? Are you going to use soft delete? Do we need CRUD API and who will do this boring job?

JPA is a de-facto standard for creating a data model for Java applications. This API does not provide facilities to implement advanced security or soft delete, so developers have to implement their own solutions.

Jmix framework provides a generic engine that adds extra features for applications that use JPA. The framework allows you to enjoy advanced data security, use soft delete transparently, provides generic REST API for CRUD operations and some other features without breaking JPA compatibility.

In this article, we will discuss the data access layer in Jmix, talk about what can be done with this framework and its tools, and how the data access works under the hood.

Data Model, JPA, and @JmixEntity

As a java developer that is familiar with JPA, you don’t need to learn anything new to start working with Jmix. New JPA EntityYou simply create JPA entities. Jmix provides a GUI designer that assists you with this task.

In the designer, you need to give your entity a name, select ID type (UUID, Long, Integer, String, or embedded class), and select features that will be supported:

  • Versioned — to support optimistic locks.
  • Audit of creation.
  • Audit of modification.
  • Soft Delete.

As a result, you will get a JPA class similar to this:

Java
 




x
38


 
1
@JmixEntity
2
@Table(name = "SPEAKER")
3
@Entity(name = "Speaker")
4
public class Speaker {
5
  
6
   @JmixGeneratedValue
7
   @Column(name = "ID", nullable = false)
8
   @Id
9
   private UUID id;
10
 
          
11
   @Email
12
   @Column(name = "EMAIL", unique = true)
13
   private String email;
14
 
          
15
   @Column(name = "NAME", nullable = false)
16
   @NotNull
17
   private String name;
18
 
          
19
   @Column(name = "VERSION", nullable = false)
20
   @Version
21
   private Integer version;
22
 
          
23
   @CreatedBy
24
   @Column(name = "CREATED_BY")
25
   private String createdBy;
26
 
          
27
   @LastModifiedBy
28
   @Column(name = "LAST_MODIFIED_BY")
29
   private String lastModifiedBy;
30
 
          
31
   @DeletedDate
32
   @Column(name = "DELETED_DATE")
33
   @Temporal(TemporalType.TIMESTAMP)
34
   private Date deletedDate;
35
 
          
36
   //Some columns, getters and setters are omitted
37
}



Please note that Jmix is not invasive. The entity does not implement even a single framework-specific interface not to mention inheriting a class, just adds some extra annotations. This gives you great flexibility in creating your own application-specific entity hierarchies that fully meet your business requirements.

Most of the annotations used by Jmix are either from JPA or from Spring Boot JPA libraries: @Entity, @Versioned, @CreatedBy, @LastModifiedBy — you could have seen them before. The framework relies on Spring Boot implementation to support optimistic locking, as well as creation and update audit.

Let me bring your attention to some Jmix-specific annotations that you will see in your data model:

  • @JmixEntity — instructs Jmix data access layer to add this class to entities repository
  • @JmixGeneratedValue — indicates that the entity’s ID attribute value must be generated and assigned by Jmix
  •  @DeletedBy and @DeletedDate — used to mark fields that indicate that the entity was deleted when you use the soft delete approach

You may ask a question: 'What is an entity repository in Jmix’s data access layer? Do you have your own data access engine?' Yes and no. The framework stores extra information about the application’s data model — metamodel, and adds a special facility — DataManager — for data access, but still uses standard JPA under the hood.

Metamodel and DataManager

Jmix is based on the Spring Boot framework. The latter is known for its extensive usage of the IoC pattern that implies storing all data about beans in the special repository — ApplicationContext. In addition to this, Jmix stores all data about your application data model (e.g. metadata) in another repository — Metadata.

Metadata is the heart of the data access layer in Jmix. It contains all the information about entities, attributes, entity associations, etc. This information is collected once at the boot time during class scanning and used by Jmix to do its magic: from row-based security to two-way data binding in the generated admin UI.

To utilize the Jmix data access layer efficiently, you need to use the DataManager component. It is a wrapper for the well-known EntityManager from JPA. Similar to EntityManager, DataManager can load entities using JPQL query or ID, save or delete entities as well as count selected instances.

Here are the examples of  DataManager usage.

Load one instance by ID using java class as a parameter:

Java
 




xxxxxxxxxx
1


 
1
Speaker loadSpeakerById(UUID speakerId) {
2
    return dataManager.load(Speaker.class) 
3
            .id(customerId)                 
4
            .one();                         
5
}



Load data using JPQL query string:

Java
 




xxxxxxxxxx
1


 
1
List<Speaker> loadSpeakesByCompanyEmail() {
2
    return dataManager.load(Speaker.class)
3
            .query("select s from Speaker s where s.email like :email")
4
            .parameter("email", "%@company.com")
5
            .list();
6
}



DataManager uses Metamodel to provide some extra features by intercepting and modifying requests to the application database before passing them to EntityManager for execution.

Let’s have a closer look at the features that Jmix provides.

Advanced Data Security

The first thing that should be mentioned — Jmix data security subsystem. The framework uses role-based security and defines two types of roles:

  1. Resource role — gives users permissions to access objects and perform specific operations in the system: CRUD operations over entities, entity attributes, UI screens, and so on.
  2. Row-level role — allows you to restrict access to particular rows of data, in other words: to entity instances.

For the resource role, you can define policies for entity CRUD operations and even operations allowed for entity’s attributes.

Java
 




xxxxxxxxxx
1
11


 
1
@ResourceRole(name = "Speaker Admin", code = "speaker-admin-role")
2
public interface SpeakerAdminRole {
3
 
          
4
   @EntityPolicy(entityName = "Speaker", 
5
                 actions = {EntityPolicyAction.ALL})
6
   @EntityAttributePolicy(entityName = "Speaker", 
7
                          attributes = "{name, email}", 
8
                          action = EntityAttributePolicyAction.MODIFY)
9
   void speakersAccess();
10
}



To implement this, DataManager analyzes JPQL and either restrict its execution or modifies the attributes list to comply with security policies.

To define a row-level role you should specify a JPQL policy that consists of the where and optional join clauses that restrict data selected from the DB table.

Java
 




xxxxxxxxxx
1
10
9


 
1
@RowLevelRole(name = "Speaker's Talks",
2
             code = "speakers-talks-role")
3
public interface SpeakersTalksRole {
4
 
          
5
   @JpqlRowLevelPolicy(entityClass = Talk.class,
6
                       where = "{E}.speaker.id = :current_user_id")
7
   void accessibleTalks();
8
 
          
9
}


So, all queries that are issued by a user with a row-level role are transformed in the following way: the where clause is appended to the existing clause using AND operator, and the join condition is appended to the existing one. If either of them does not exist in the JPQL, the corresponding clause is 'just' appended.

Metadata repository plays an important role here. It helps us to parse and modify JPQL correctly and find out restricted attributes and entities whenever string JPQL or Java class is used to define a DB query.

Soft Delete

In some cases, soft delete is required for enterprise applications. The pros and cons of the soft delete pattern were discussed in the article 'To Delete or to Soft Delete, That is the Question!' in the CUBA Platform blog. Jmix is a descendant of CUBA, so soft delete is supported in this framework, too.

Soft Delete mode is enabled automatically for entities with the fields annotated with @DeletedBy and @DeletedDate. For these entities, all remove() invocations in DataManager are intercepted and transformed to UPDATE statements, and all find() requests will be modified with an appropriate where clause to exclude 'deleted' entities.

Java
 




xxxxxxxxxx
1
22


 
1
@JmixEntity
2
@Table(name = "SPEAKER")
3
@Entity(name = "Speaker")
4
public class Speaker {
5
 
          
6
   @JmixGeneratedValue
7
   @Column(name = "ID", nullable = false)
8
   @Id
9
   private UUID id;
10
 
          
11
   @DeletedBy
12
   @Column(name = "DELETED_BY")
13
   private String deletedBy;
14
 
          
15
   @DeletedDate
16
   @Column(name = "DELETED_DATE")
17
   @Temporal(TemporalType.TIMESTAMP)
18
   private Date deletedDate;
19
 
          
20
      //Some fields are omitted
21
}



We need Metadata here to find out which database column should be updated or added to where clause. In contrast to CUBA, Jmix does not require an entity to implement a specific interface to support soft delete. All you need to do is just add two annotations to the entity’s fields.

Note that you still can perform 'hard delete' and see the 'deleted' entities using JPA EntityManager and native SQL.

REST and GraphQL

Automatic CRUD API creation is the area where Jmix’s metamodel shines. When you have all the information about entities in your application, it is pretty easy to create an API for manipulation.

For example, it should not be hard to handle HTTP requests like this if you have metadata for your data model:

GET 'http://server:8080/rest/entities/Speaker'

A single endpoint at `/rest/entities` can handle requests for entity manipulations. The application 'knows' which entities should be selected if a user sends the GET request for an entity (`Speaker` in our example). Moreover, it costs nothing for an application to provide a Swagger-compatible endpoints schema because we have all metadata we need.

Jmix can generate a swagger doc that includes all entities and attributes that a developer can process via REST API, and make available on a specific URL:

GET 'http://server:8080/rest/docs/swagger.json'

For example, a list of endpoints for CRUD operations looks like this:

CRUD entities operations

The good thing is that with Jmix you don’t need to do the boring job of implementing these endpoints manually. Thanks to the metamodel, everything can be generated for you, and it can be a good starting point to build your own specific REST API using the 'back-for-the-front' approach.

If you need something more flexible than generic CRUD REST API, you can use GraphQL. One of the key concepts in GraphQL is its schema. With Jmix’s metamodel, we have all the data for the GraphQL schema without extra effort.

It means that GraphQL API for Jmix applications can be implemented (and it is going to be released soon) in a generic way, similar to the REST API. So, adding GraphQL endpoint to your Jmix application will be as simple as adding one more starter to the build script.

implementation 'io.jmix.graphql:jmix-graphql-starter'

After that, you are able to create queries similar to this:

JSON
 




xxxxxxxxxx
1


 
1
{
2
  speakerCount
3
  speakerList(limit: 10, offset: 0, orderBy: {name: ASC}) {
4
    id
5
    name
6
    email
7
  }
8
}



Conclusion

Just by defining the data model in Jmix, mostly using familiar JPA annotations, you’re getting a ready-to-use application. Thanks to Jmix’s metamodel, you can use the following features almost without extra coding:

  • Row-level security.
  • Soft delete.
  • CRUD REST API.
  • GraphQL API.

As you see, creating a simple data-centric application with advanced features and admin UI is going to be near trivial with Jmix.

Data security Data access Database Data access layer Spring Framework application

Opinions expressed by DZone contributors are their own.

Related

  • Controlling Access to Google BigQuery Data
  • Enterprise RIA With Spring 3, Flex 4 and GraniteDS
  • Data Security Considerations in Cloud Data Warehouses
  • How To Build Web Service Using Spring Boot 2.x

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!