Skip to main content

OPA Java Tutorial: Hello World

This Hello World style tutorial explains how to set up a basic Java project which is able to import the OPA Java SDK and use it to evaluate a policy decision.

Setup

In a new directory, run gradle init. The prompts should be responded to as follows:

  • Select type of build to generate: Application
  • Select implementation language: Java
  • Enter target Java version: 21
  • Project name: docsample
  • Select application structure: Single application project
  • Select build script DSL: Groovy
  • Select test framework: JUnit Jupiter
  • Generate build using new APIs and behavior: no

Gradle should print a message like the one below if everything went right.

BUILD SUCCESSFUL in 3m 56s
1 actionable task: 1 executed

Before proceeding, verify that the project Gradle created for us is able to build and run. The output should look similar to the below.

./gradlew run

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 627ms
2 actionable tasks: 2 executed

Adding the OPA Java SDK

Next, modify the Java code to utilize the OPA Java SDK in app/src/main/java/org/example/App.java

/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;

import com.styra.opa.OPAClient;
import com.styra.opa.OPAException;

import java.util.Map;
import java.util.List;

import static java.util.Map.entry;

public class App {
public String getGreeting() {
return "Hello World!";
}

public static void main(String[] args) {
public static void main(String[] args) throws OPAException {
System.out.println(new App().getGreeting());

// Create an OPA instance, this handles any state needed for interacting
// with OPA, and can be re-used for multiple requests if needed.
String opaURL = "http://localhost:8181";
OPAClient opa = new OPAClient(opaURL);

// This will be the input to our policy.
java.util.Map<String,Object> input = java.util.Map.ofEntries(
entry("subject", "alice"),
entry("action", "read"),
entry("resource", "/finance/reports/fy2038_budget.csv")
);

boolean allowed = false;

// Perform the request against OPA.
try {
allowed = opa.check("authz/allow", input);
} catch (OPAException e ) {
// Note that OPAException usually wraps other exception types, in
// case you need to do more complex error handling.
System.out.println("exception while making request against OPA: " + e);
throw e; // crash the program
}

System.out.println("allowed: " + allowed);
}
}

The app/build.gradle file must also be updated to pull in the OPA-Java SDK. Under the dependencies section, add the following:

    implementation group: 'com.styra', name: 'opa', version: '+'
warning

Using the version string + causes Gradle to pull in the latest version of that dependency. In a production environment, it may be preferable to pin a specific version of your dependencies instead.

Creating policies and running OPA

The sample application is almost ready to run, but first an OPA instance is needed for the SDK to communicate with.

Create a policy/ folder and the following two files:

policy/authz/authz.rego

package authz

import rego.v1

default allow := false

allow if input.subject == "alice"

policy/data.json

{
"roles": {
"admin": ["read", "write"]
}
}

Next, launch OPA in a separate terminal window:

opa run --server --bundle ./policy/

In the original terminal window, verify that the data was loaded into OPA correctly:

curl -Ss http://localhost:8181/v1/data/roles
{"result":{"admin":["read","write"]}}

Verify that the policy is working as expected:

curl -Ss http://localhost:8181/v1/data/authz/allow -X POST -d '{"input": {"subject": "alice"} }'
{"result":true}
curl -Ss http://localhost:8181/v1/data/authz/allow -X POST -d '{"input": {"subject": "bob"} }'
{"result":false}

Running the application

Finally, run the Java program:

./gradlew run

> Task :app:run
Hello World!
allowed: true

BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed

Notice the addition of the response from OPA.

The project is now prepared for experimenting with the OPA Java SDK locally. Try modifying App.java or the OPA policy and see how the behavior changes.


Final Code

app/src/main/java/org/example/App.java:

/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;

import com.styra.opa.OPAClient;
import com.styra.opa.OPAException;

import java.util.Map;
import java.util.List;

import static java.util.Map.entry;

public class App {
public String getGreeting() {
return "Hello World!";
}

public static void main(String[] args) throws OPAException {
System.out.println(new App().getGreeting());

// Create an OPA instance, this handles any state needed for interacting
// with OPA, and can be re-used for multiple requests if needed.
String opaURL = "http://localhost:8181";
OPAClient opa = new OPAClient(opaURL);

// This will be the input to our policy.
java.util.Map<String,Object> input = java.util.Map.ofEntries(
entry("subject", "alice"),
entry("action", "read"),
entry("resource", "/finance/reports/fy2038_budget.csv")
);

boolean allowed = false;

// Perform the request against OPA.
try {
allowed = opa.check("authz/allow", input);
} catch (OPAException e ) {
// Note that OPAException usually wraps other exception types, in
// case you need to do more complex error handling.
System.out.println("exception while making request against OPA: " + e);
throw e; // crash the program
}

System.out.println("allowed: " + allowed);
}
}