OPA Java SDK Usage
Installation
The Java SDK is published on Maven Central as com.styra/opa
. The Maven Central page includes up-to-date instructions to add it as a dependency to your Java project, tailored for a variety of build systems including Maven and Gradle.
Code Examples
The following examples assume an OPA server at http://localhost:8181
equipped with the following Rego policy:
package authz
import rego.v1
default allow := false
allow if input.subject == "alice"
and this data:
{
"roles": {
"admin": ["read", "write"]
}
}
Simple Query
For a simple boolean response with input, use the SDK as follows:
String opaURL = "http://localhost:8181";
OPAClient opa = new OPAClient(opaURL);
java.util.Map<String,Object> input = java.util.Map.ofEntries(
entry("subject", "alice"),
entry("action", "read"),
);
boolean allowed = false;
try {
allowed = opa.check("authz/allow", input);
} catch (OPAException e ) {
System.out.println("exception while making request against OPA: " + e);
}
System.out.println("allowed: " + allowed);
Simple Query with Output
The .evaluate()
method can be used instead of .check()
for non-boolean output types:
String opaURL = "http://localhost:8181";
OPAClient opa = new OPAClient(opaURL);
java.util.Map<String,Object> input = java.util.Map.ofEntries(
entry("subject", "alice"),
entry("action", "read"));
java.util.Map<String, Object> out = null;
try {
out = opa.evaluate("roles", input);
} catch (OPAException e ) {
System.out.println("exception while making request against OPA: " + e);
}
System.out.println("content of data.roles: " + out);
Objects for Input And Output
In Java, it can be more natural to use objects as inputs and outputs to a policy, rather than java.util.Map
. This is fully supported by OPA-Java, including objects with type parameters. Internally, OPA-Java uses Jackson to handle converting between the JSON OPA consumes and emits, and native Java types. Due to type erasure, an implementation detail of Java's generics, deserializing OPA outputs into most types of classes, including the one in this example require an additional type reference argument which tells Jackson what type of class to deserialize the output into.
If you see an error such as:
Exception in thread "main" java.lang.ClassCastException:
It is likely you forgot the type reference argument to evaluate()
.
This is a minimal representative example for how to "round-trip"'; the input is Java object with a type parameter and so is the output.
// import com.fasterxml.jackson.core.type.TypeReference;
String opaURL = "http://localhost:8181";
OPAClient opa = new OPAClient(opaURL);
CustomContainer<Integer> in = new CustomContainer<Integer>();
in.setName("meaning of life");
in.setValue(42);
CustomContainer<String> out = null;
try {
out = opa.evaluate("obj/stringify", in, new TypeReference<CustomContainer<String>>() {});
} catch (OPAException e ) {
System.out.println("exception while making request against OPA: " + e);
}
System.out.println("out.getName(): " + out.getName());
System.out.println("out.getValue(): " + out.getValue());
To run this example, the following needs to added to the OPA policy by placing it in policy/obj/obj.rego
:
package obj
stringify := {
"value": sprintf("%v", [input.value]),
"name": sprintf("%s (stringified)", [input.name]),
}
Additionally, the definition of CustomContainer
must be placed at app/src/main/java/org/example/CustomContainer.java
:
package org.example;
public class CustomContainer<T> {
private T value;
private String name;
public void setValue(T newValue) {
this.value = newValue;
}
public T getValue() {
return this.value;
}
public void setName(String newName) {
this.name = newName;
}
public String getName() {
return this.name;
}
}
Batched Queries
import com.styra.opa.OPAClient;
import com.styra.opa.OPAException;
import com.styra.opa.OPAResult;
import java.util.Map;
import static java.util.Map.entry;
String opaURL = "http://localhost:8181";
OPAClient opa = new OPAClient(opaURL);
Map<String,Object> alice = Map.ofEntries(
entry("subject", "alice"),
entry("action", "read"),
entry("resource", "/finance/reports/fy2038_budget.csv")
);
Map<String,Object> bob = Map.ofEntries(
entry("subject", "bob"),
entry("action", "write"),
entry("resource", "/finance/reports/fy2038_budget.csv")
);
Map<String,Object> input = Map.ofEntries(
entry("alice", alice),
entry("bob", bob)
);
Map<String,OPAResult> responses;
try {
responses = opa.evaluateBatch("authz/allow", input);
for (var entry : responses.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue().get());
}
} catch (OPAException e ) {
System.out.println("exception while making request against OPA: " + e);
throw e;
}
Result
bob: false
alice: true