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
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Configurable Feign Client Retry With Reusable Library and DRY
  • That’s How You Can Use MapStruct With Lombok in Your Spring Boot Application
  • Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot
  • A Spring Boot App With Half the Startup Time

Trending

  • Metal Default, a New Build Cloud, and a New Format
  • The Hidden Cost of AI Tokens: Engineering Patterns for 10x Resource Efficiency
  • Why AI-Generated Code Breaks Your Testing Assumptions
  • Production-Grade RAG: Why Vector Search Isn't Enough (and How Hybrid Search Fills the Gaps)
  1. DZone
  2. Coding
  3. Frameworks
  4. Runtime Formula Evaluation With MVEL Library in Spring Boot

Runtime Formula Evaluation With MVEL Library in Spring Boot

Learn how to use MVEL in Spring Boot to move business rules into the database, reduce deployments, and support dynamic runtime calculations.

By 
Erkin Karanlık user avatar
Erkin Karanlık
·
Jun. 16, 26 · Analysis
Likes (0)
Comment
Save
Tweet
Share
223 Views

Join the DZone community and get the full member experience.

Join For Free

In our software development processes, business units constantly want to update discount rates, loyalty points, or salary calculation logic.

If this logic is within the code, between when-or-if-else blocks, every change means a new unit test process, code analysis, CI/CD pipeline work, and ultimately a "deployment."

In this article, we will separate the business logic from the code, making it manageable in the database and reliably interpretable at runtime. By increasing flexibility, we will ensure the system's stable operation continues without interruption.

To do all this, we will examine how to use the MVEL (MVFLEX Expression Language) library below.

The Cost of Static Code: Why Should We Avoid It?

Generally, point calculations are as follows:

Kotlin
 
fun calculatePoints(pointType: String, factor: Int): Long {
    return when (pointType) {
        "INITIAL"        -> 100L
        "BIRTHDAY"       -> 50L
        "TENURE_5_10"    -> factor * 10L
        "TENURE_10_20"   -> factor * 20L
        "TENURE_20_PLUS" -> factor * 30L
        else             -> 0L
    }
}


When looking at the code, what appears is more of a maintenance burden than a simple function. If the factors change or a new rule is added, the code is triggered from the beginning.

However, these values are actually data, not code.

Architectural Approach

Below, you will find how it works when we add the Formula engine.

Kotlin
 
import org.mvel2.MVEL

val formula = "factor * 20"
val vars = mapOf("factor" to 5)
val result = MVEL.eval(formula, vars)


In this architecture, the code does not know "how to calculate"; It only knows how to call the 'Formula engine.'

Database Design

Converting Rules to Data

We can store business rules in a flexible table. This ensures manageability.

PLSQL
 
CREATE TABLE t_point_type (
    point_type_id    NUMBER PRIMARY KEY,
    point_type_name  VARCHAR2(100),
    point_formula    VARCHAR2(500),   
    description      VARCHAR2(1000)
);


Sample data:

Plain Text
 
| point_type_id | point_type_name | point_formula           |
|:-------------:|:---------------:|:-----------------------:|
| 1             | INITIAL         | `100`                   |
| 2             | BIRTHDAY        | `50`                    |
| 3             | TENURE_5_10     | `factor * 10`           |
| 4             | TENURE_10_20    | `factor * 20`           |
| 5             | TENURE_20_PLUS  | `factor * 30`           |
| 6             | PROMOTIONAL     | `factor * multiplier`   |


Application Layer

The most critical point to consider in MVEL integration is performance and error management.

1. Entity Definition

Kotlin
 
@Entity
@Table(name = "t_point_type")
data class PointTypeEntity(
    @Id
    @Column(name = "point_type_id")
    val pointTypeId: Long? = null,

    @Column(name = "point_type_name")
    val pointTypeName: String? = null,

    @Column(name = "point_formula")
    val pointFormula: String? = null
)


2. MvelUtil: Performance-Oriented Helper Class

Considering the CPU cost of parsing strings in every request, we should use compiled expressions and caching mechanisms.

Kotlin
 
@Component
class MvelUtil {

    fun evaluateFormula(formula: String, factor: Int): Long {
        return try {
            val variables = mapOf("factor" to factor)
            val result = MVEL.eval(formula, variables)
            when (result) {
                is Number -> result.toLong()
                else -> 0L
            }
        } catch (e: Exception) {
            throw BusinessException(
                errorCode = ErrorCodes.MVEL_FORMULA_EVALUATION_FAILED,
                errorDesc = "Formula evaluation failed: $formula, factor: $factor — ${e.message}"
            )
        }
    }

    fun evaluateFormulaAsString(formula: String, factor: Int): String {
        return try {
            val variables = mapOf("factor" to factor)
            MVEL.eval(formula, variables).toString()
        } catch (e: Exception) {
            throw BusinessException(
                errorCode = ErrorCodes.MVEL_FORMULA_EVALUATION_FAILED,
                errorDesc = "Formula evaluation failed.: $formula — ${e.message}"
            )
        }
    }
}


3. Service Layer and Business Logic

Therefore, our service layer simply receives the data and triggers the formula engine.

Kotlin
 
@Service
class PointCalculationService(
    private val pointTypeRepository: PointTypeRepository,
    private val mvelUtil: MvelUtil
) {

    fun calculatePoints(pointTypeId: Long, factor: Int): Long {
        val pointType = pointTypeRepository.findById(pointTypeId)
            .orElseThrow { BusinessException(ErrorCodes.POINT_TYPE_NOT_FOUND) }

        val formula = pointType.pointFormula
            ?: throw BusinessException(ErrorCodes.POINT_FORMULA_NOT_DEFINED)

        val points = mvelUtil.evaluateFormula(formula, factor)

        if (points <= 0) {
            log.info("The formula gave a score of 0 or negative: type=$pointTypeId, factor=$factor")
            return 0L
        }

        return points
    }
}


Call service:

Kotlin
 
val factor = inputData.factorSpecificForPoint ?: 1
val points = calculatePoints(inputData.pointTypeId, factor)

if (points > 0) {
    savePointDetail(points, subscriptionId, inputData.pointTypeId, inputData.operationId)
}


Advanced Usage: Multivariable and Conditional Formulas

MVEL has the ability to decode complex strings. Its true power lies in this.

For example, the formula in the database might look like this:

SQL
 
UPDATE t_point_type 
SET point_formula = 'factor * multiplier + bonus'
WHERE point_type_id = 6;
Kotlin
 
fun evaluateWithMultipleVars(formula: String, vars: Map<String, Any>): Long {
    return try {
        val result = MVEL.eval(formula, vars)
        (result as? Number)?.toLong() ?: 0L
    } catch (e: Exception) {
        throw BusinessException(ErrorCodes.MVEL_FORMULA_EVALUATION_FAILED)
    }
}

val vars = mapOf("factor" to 5, "multiplier" to 3, "bonus" to 10)
evaluateWithMultipleVars("factor * multiplier + bonus", vars)  


Conditional Statements

MVEL supports ternary expressions and Boolean logic:

Plain Text
 
factor > 10 ? factor * 20 : factor * 10
(factor >= 5 && factor < 10) ? 50 : (factor >= 10 ? 100 : 25)


This provides truly dynamic rules without any code changes.

We must not ignore these three rules, as everything is necessary;

  • Strict validation: The formula must be validated with MVEL.compileExpression() before being saved to the database. An incorrect syntax error can disrupt the entire flow at runtime.
  • Sandbox and security: MVEL is robust; it can access Java classes. Therefore, formula entry should only be done from authorized (admin) panels, and if necessary, MVEL's secure mode should be configured.
  • Default value: There can always be a fallback mechanism. We determine how the system will behave if the formula receives an error or the result returns null (e.g., 0 points).

Conclusion

MVEL makes it easy for us to dynamically implement business rules in Spring Boot projects.

It reduces code complexity while allowing you to respond to business unit requests within minutes (without deployment!).

XML
 
Dependency (Maven):

XML
<dependency>
<groupId>org.mvel</groupId> 
<artifactId>mvel2</artifactId> 
<version>2.5.0.Final</version>
</dependency>


Evaluation Library Spring Boot

Opinions expressed by DZone contributors are their own.

Related

  • Configurable Feign Client Retry With Reusable Library and DRY
  • That’s How You Can Use MapStruct With Lombok in Your Spring Boot Application
  • Parallel Kafka Batch Processing With Kotlin Coroutines in Spring Boot
  • A Spring Boot App With Half the Startup Time

Partner Resources

×

Comments

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

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

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 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook