diff --git a/Makefile b/Makefile
index b889d85..b05df5c 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@ help:
@echo " test-integration - Run all integration tests"
@echo " test-integration-csharp - Run C# integration tests"
@echo " test-integration-go - Run Go integration tests"
+ @echo " test-integration-java - Run Java integration tests"
@echo " test-integration-nodejs - Run NodeJS integration tests"
@echo " generate - Generate all code (API clients, docs, schema)"
@echo " generate-api - Generate API clients from OpenAPI specs"
@@ -67,6 +68,11 @@ test-integration-angular:
@echo "Running Angular integration test with Dagger..."
@go run ./test/integration/cmd/angular/run.go
+.PHONY: test-integration-java
+test-integration-java:
+ @echo "Running Java integration test with Dagger..."
+ @go run ./test/integration/cmd/java/run.go
+
.PHONY: test-integration
test-integration:
@echo "Running all integration tests with Dagger..."
diff --git a/test/integration/cmd/java/run.go b/test/integration/cmd/java/run.go
new file mode 100644
index 0000000..b5c67cb
--- /dev/null
+++ b/test/integration/cmd/java/run.go
@@ -0,0 +1,95 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "dagger.io/dagger"
+ "github.com/open-feature/cli/test/integration"
+)
+
+// Test implements the integration test for the Java generator
+type Test struct {
+ // ProjectDir is the absolute path to the root of the project
+ ProjectDir string
+ // TestDir is the absolute path to the test directory
+ TestDir string
+}
+
+// New creates a new Test
+func New(projectDir, testDir string) *Test {
+ return &Test{
+ ProjectDir: projectDir,
+ TestDir: testDir,
+ }
+}
+
+// Run executes the Java integration test using Dagger
+func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) {
+ // Source code container
+ source := client.Host().Directory(t.ProjectDir)
+ testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{
+ Include: []string{"pom.xml", "src/**/*.java"},
+ })
+
+ // Build the CLI
+ cli := client.Container().
+ From("golang:1.24-alpine").
+ WithExec([]string{"apk", "add", "--no-cache", "git"}).
+ WithDirectory("/src", source).
+ WithWorkdir("/src").
+ WithExec([]string{"go", "mod", "tidy"}).
+ WithExec([]string{"go", "mod", "download"}).
+ WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"})
+
+ // Generate Java client
+ generated := cli.WithExec([]string{
+ "./cli", "generate", "java",
+ "--manifest=/src/sample/sample_manifest.json",
+ "--output=/tmp/generated",
+ "--package-name=dev.openfeature.generated",
+ })
+
+ // Get generated files
+ generatedFiles := generated.Directory("/tmp/generated")
+
+ // Test Java compilation with the generated files
+ javaContainer := client.Container().
+ From("maven:3.9-eclipse-temurin-21-alpine").
+ WithWorkdir("/app").
+ WithDirectory("/app", testFiles).
+ WithDirectory("/app/src/main/java/dev/openfeature/generated", generatedFiles).
+ WithExec([]string{"mvn", "clean", "compile", "-B", "-q"}).
+ WithExec([]string{"mvn", "exec:java", "-Dexec.mainClass=dev.openfeature.Main", "-q"})
+
+ return javaContainer, nil
+}
+
+// Name returns the name of the integration test
+func (t *Test) Name() string {
+ return "java"
+}
+
+func main() {
+ ctx := context.Background()
+
+ // Get project root
+ projectDir, err := os.Getwd()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get project dir: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Get test directory
+ testDir := filepath.Join(projectDir, "test/java-integration")
+
+ // Create and run the Java integration test
+ test := New(projectDir, testDir)
+
+ if err := integration.RunTest(ctx, test); err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+ os.Exit(1)
+ }
+}
diff --git a/test/integration/cmd/run.go b/test/integration/cmd/run.go
index 5923c26..e75acaf 100644
--- a/test/integration/cmd/run.go
+++ b/test/integration/cmd/run.go
@@ -45,6 +45,15 @@ func main() {
os.Exit(1)
}
+ // Run the Java integration test
+ javaCmd := exec.Command("go", "run", "github.com/open-feature/cli/test/integration/cmd/java")
+ javaCmd.Stdout = os.Stdout
+ javaCmd.Stderr = os.Stderr
+ if err := javaCmd.Run(); err != nil {
+ fmt.Fprintf(os.Stderr, "Error running Java integration test: %v\n", err)
+ os.Exit(1)
+ }
+
// Add more tests here as they are available
fmt.Println("=== All integration tests passed successfully ===")
diff --git a/test/java-integration/pom.xml b/test/java-integration/pom.xml
new file mode 100644
index 0000000..d1bc7c7
--- /dev/null
+++ b/test/java-integration/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+ dev.openfeature
+ cli-java-integration-test
+ 1.0-SNAPSHOT
+
+
+ 21
+ 21
+ UTF-8
+ 1.14.0
+ 3.11.0
+ 3.1.0
+
+
+
+
+
+ dev.openfeature
+ sdk
+ ${openfeature.sdk.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ ${exec-maven-plugin.version}
+
+ dev.openfeature.Main
+
+
+
+
+
diff --git a/test/java-integration/src/main/java/dev/openfeature/Main.java b/test/java-integration/src/main/java/dev/openfeature/Main.java
new file mode 100644
index 0000000..5d6a2d1
--- /dev/null
+++ b/test/java-integration/src/main/java/dev/openfeature/Main.java
@@ -0,0 +1,103 @@
+package dev.openfeature;
+
+import dev.openfeature.generated.*;
+import dev.openfeature.sdk.*;
+import dev.openfeature.sdk.providers.memory.Flag;
+import dev.openfeature.sdk.providers.memory.InMemoryProvider;
+
+import java.util.Map;
+
+public class Main {
+ public static void main(String[] args) {
+ try {
+ run();
+ System.out.println("Generated Java code compiles successfully!");
+ } catch (Exception e) {
+ System.err.println("Error: " + e.getMessage());
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void run() throws Exception {
+ // Set up the in-memory provider with test flags
+ Map themeConfig = Map.of(
+ "primaryColor", "#007bff",
+ "secondaryColor", "#6c757d"
+ );
+
+ Map> flags = Map.of(
+ "discountPercentage", Flag.builder()
+ .variant("default", 0.15)
+ .defaultVariant("default")
+ .build(),
+ "enableFeatureA", Flag.builder()
+ .variant("default", false)
+ .defaultVariant("default")
+ .build(),
+ "greetingMessage", Flag.builder()
+ .variant("default", "Hello there!")
+ .defaultVariant("default")
+ .build(),
+ "usernameMaxLength", Flag.builder()
+ .variant("default", 50)
+ .defaultVariant("default")
+ .build(),
+ "themeCustomization", Flag.builder()
+ .variant("default", new Value(themeConfig))
+ .defaultVariant("default")
+ .build()
+ );
+
+ InMemoryProvider provider = new InMemoryProvider(flags);
+
+ // Set the provider
+ OpenFeatureAPI.getInstance().setProviderAndWait(provider);
+
+ Client client = OpenFeatureAPI.getInstance().getClient();
+ MutableContext evalContext = new MutableContext();
+
+ // Use the generated code for all flag evaluations
+ Boolean enableFeatureA = EnableFeatureA.value(client, evalContext);
+ System.out.println("enableFeatureA: " + enableFeatureA);
+ FlagEvaluationDetails enableFeatureADetails = EnableFeatureA.valueWithDetails(client, evalContext);
+ if (enableFeatureADetails.getErrorCode() != null) {
+ throw new Exception("Error evaluating boolean flag: " + enableFeatureADetails.getFlagKey());
+ }
+
+ Double discount = DiscountPercentage.value(client, evalContext);
+ System.out.printf("Discount Percentage: %.2f%n", discount);
+ FlagEvaluationDetails discountDetails = DiscountPercentage.valueWithDetails(client, evalContext);
+ if (discountDetails.getErrorCode() != null) {
+ throw new Exception("Failed to get discount for flag: " + discountDetails.getFlagKey());
+ }
+
+ String greetingMessage = GreetingMessage.value(client, evalContext);
+ System.out.println("greetingMessage: " + greetingMessage);
+ FlagEvaluationDetails greetingDetails = GreetingMessage.valueWithDetails(client, evalContext);
+ if (greetingDetails.getErrorCode() != null) {
+ throw new Exception("Error evaluating string flag: " + greetingDetails.getFlagKey());
+ }
+
+ Integer usernameMaxLength = UsernameMaxLength.value(client, evalContext);
+ System.out.println("usernameMaxLength: " + usernameMaxLength);
+ FlagEvaluationDetails usernameDetails = UsernameMaxLength.valueWithDetails(client, evalContext);
+ if (usernameDetails.getErrorCode() != null) {
+ throw new Exception("Error evaluating int flag: " + usernameDetails.getFlagKey());
+ }
+
+ Value themeCustomization = ThemeCustomization.value(client, evalContext);
+ FlagEvaluationDetails themeDetails = ThemeCustomization.valueWithDetails(client, evalContext);
+ if (themeDetails.getErrorCode() != null) {
+ throw new Exception("Error evaluating object flag: " + themeDetails.getFlagKey());
+ }
+ System.out.println("themeCustomization: " + themeCustomization);
+
+ // Test the getKey() method functionality for all flags
+ System.out.println("enableFeatureA flag key: " + EnableFeatureA.getKey());
+ System.out.println("discountPercentage flag key: " + DiscountPercentage.getKey());
+ System.out.println("greetingMessage flag key: " + GreetingMessage.getKey());
+ System.out.println("usernameMaxLength flag key: " + UsernameMaxLength.getKey());
+ System.out.println("themeCustomization flag key: " + ThemeCustomization.getKey());
+ }
+}