Skip to content

Commit 8d48e62

Browse files
feat: run Java dedup as java agent
Adds Java-agent support for Java dynamic dedup and prepares io.keploy:keploy-sdk:2.0.0 as the runtime agent artifact.\n\nSigned-off-by: Asish Kumar <officialasishkumar@gmail.com>
1 parent c83b581 commit 8d48e62

7 files changed

Lines changed: 424 additions & 60 deletions

File tree

.github/workflows/java-agent.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Java Agent
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
jobs:
10+
verify:
11+
name: JDK ${{ matrix.java-version }}
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
java-version: ["8", "17", "21"]
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Set up JDK ${{ matrix.java-version }}
23+
uses: actions/setup-java@v4
24+
with:
25+
distribution: temurin
26+
java-version: ${{ matrix.java-version }}
27+
cache: maven
28+
29+
- name: Build
30+
run: mvn -B -DskipTests clean verify
31+
32+
- name: Smoke test Java agent
33+
run: ./scripts/smoke-javaagent.sh

.woodpecker/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ steps:
1818
image: maven:3.9-eclipse-temurin-8
1919
commands:
2020
- mvn -B -DskipTests clean verify
21+
- ./scripts/smoke-javaagent.sh
2122

2223
build-jdk-17:
2324
image: maven:3.9-eclipse-temurin-17
2425
commands:
2526
- mvn -B -DskipTests clean verify
27+
- ./scripts/smoke-javaagent.sh
2628

2729
build-jdk-21:
2830
image: maven:3.9-eclipse-temurin-21
2931
commands:
3032
- mvn -B -DskipTests clean verify
33+
- ./scripts/smoke-javaagent.sh

README.md

Lines changed: 41 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,78 +23,69 @@ Coverage is collected at per-testcase granularity, not process granularity.
2323

2424
## How to Use
2525

26-
### 1. Add the SDK
26+
### 1. Download the Keploy Java Agent
2727

28-
Add `keploy-sdk` to your application:
28+
Download the `keploy-sdk` jar and keep it outside your application dependencies. The jar is a Java agent and should be attached only when you run Keploy dynamic deduplication.
2929

3030
```xml
31-
<dependency>
32-
<groupId>io.keploy</groupId>
33-
<artifactId>keploy-sdk</artifactId>
34-
<version>2.0.0</version>
35-
</dependency>
31+
<plugin>
32+
<groupId>org.apache.maven.plugins</groupId>
33+
<artifactId>maven-dependency-plugin</artifactId>
34+
<version>3.6.1</version>
35+
<executions>
36+
<execution>
37+
<id>copy-keploy-java-agent</id>
38+
<phase>package</phase>
39+
<goals>
40+
<goal>copy</goal>
41+
</goals>
42+
<configuration>
43+
<artifactItems>
44+
<artifactItem>
45+
<groupId>io.keploy</groupId>
46+
<artifactId>keploy-sdk</artifactId>
47+
<version>2.0.0</version>
48+
<outputDirectory>${project.build.directory}</outputDirectory>
49+
<destFileName>keploy-sdk.jar</destFileName>
50+
</artifactItem>
51+
</artifactItems>
52+
</configuration>
53+
</execution>
54+
</executions>
55+
</plugin>
3656
```
3757

38-
### 2. Activate the Agent
58+
The SDK no longer has to be added to `dependencies`, and application code should not import `io.keploy.*` classes for dynamic deduplication.
3959

40-
For Spring Boot, import the middleware in your application:
41-
42-
```java
43-
import io.keploy.servlet.KeployMiddleware;
44-
import org.springframework.context.annotation.Import;
45-
46-
@Import(KeployMiddleware.class)
47-
public class Application {
48-
}
49-
```
50-
51-
For servlet-based applications, register the filter early in `web.xml`:
52-
53-
```xml
54-
<filter>
55-
<filter-name>middleware</filter-name>
56-
<filter-class>io.keploy.servlet.KeployMiddleware</filter-class>
57-
</filter>
58-
<filter-mapping>
59-
<filter-name>middleware</filter-name>
60-
<url-pattern>/*</url-pattern>
61-
</filter-mapping>
62-
```
63-
64-
The middleware starts the Java dedup control server automatically.
65-
66-
For Jakarta Servlet stacks, non-servlet frameworks, or any application where the `javax.servlet` filter is not available, start the agent directly during application startup:
67-
68-
```java
69-
import io.keploy.dedup.KeployDedupAgent;
70-
71-
KeployDedupAgent.start();
72-
```
73-
74-
### 3. Run the App with the JaCoCo Java Agent
60+
### 2. Run the App with the Keploy and JaCoCo Java Agents
7561

7662
The dedup agent reads coverage in-process via JaCoCo's runtime API (`org.jacoco.agent.rt.RT.getAgent()`), so attaching the JaCoCo Java agent is the only runtime requirement in the common cases below:
7763

7864
- Maven/Gradle dev runs where application classes are under `target/classes` or `build/classes/java/main`
7965
- packaged `java -jar` runs where the application classes live inside the executable jar
8066

8167
```bash
82-
java -javaagent:/path/to/jacocoagent.jar -jar your-app.jar
68+
java \
69+
-javaagent:/path/to/keploy-sdk.jar \
70+
-javaagent:/path/to/jacocoagent.jar \
71+
-jar your-app.jar
8372
```
8473

8574
If the in-process API is unavailable (for example because the JaCoCo agent is loaded into an isolated classloader), the SDK transparently falls back to JaCoCo's TCP server mode. To use the fallback explicitly, start JaCoCo in `tcpserver` mode and set `KEPLOY_JACOCO_HOST` / `KEPLOY_JACOCO_PORT`:
8675

8776
```bash
88-
java -javaagent:/path/to/jacocoagent.jar=address=127.0.0.1,port=36320,output=tcpserver \
77+
java \
78+
-javaagent:/path/to/keploy-sdk.jar \
79+
-javaagent:/path/to/jacocoagent.jar=address=127.0.0.1,port=36320,output=tcpserver \
8980
-jar your-app.jar
9081
```
9182

92-
### 4. Replay with Keploy Enterprise
83+
### 3. Replay with Keploy Enterprise
9384

9485
Run replay with dynamic dedup enabled:
9586

9687
```bash
97-
keploy test -c "java -javaagent:/path/to/jacocoagent.jar -jar your-app.jar" \
88+
keploy test -c "java -javaagent:/path/to/keploy-sdk.jar -javaagent:/path/to/jacocoagent.jar -jar your-app.jar" \
9889
--dedup \
9990
--language java
10091
```
@@ -128,8 +119,8 @@ Without a shared `/tmp`, dedup will not work inside containers because Enterpris
128119

129120
- `KEPLOY_JACOCO_HOST`: JaCoCo TCP host used when the in-process runtime API is unavailable. Default: `127.0.0.1`
130121
- `KEPLOY_JACOCO_PORT`: JaCoCo TCP port used when the in-process runtime API is unavailable. Default: `36320`
131-
- `KEPLOY_JAVA_CLASS_DIRS`: optional comma-separated class or jar locations to analyze for executed lines when your build output lives outside the standard locations
132-
- `KEPLOY_JAVA_CLASSPATH_FALLBACK`: scans the full classpath if standard class roots and the executable jar do not provide application classes. Default: `false`
122+
- `KEPLOY_JAVA_CLASS_DIRS`: optional comma-separated class, jar, war, ear, or zip locations to analyze for executed lines when your build output lives outside the standard locations
123+
- `KEPLOY_JAVA_CLASSPATH_FALLBACK`: scans the full classpath if standard class roots and the executable archive do not provide application classes. Default: `true`
133124
- `KEPLOY_JAVA_DEDUP_DISABLED`: disables the Java dedup agent when set to `true`, `1`, or `yes`
134125

135126
## Sample
@@ -138,4 +129,4 @@ For a working reference, see the Java dedup sample in `keploy/samples-java`:
138129

139130
- `samples-java/java-dedup`
140131

141-
That sample is used in CI to validate Java dynamic dedup for JDK 8, 17, and 21 across native, Docker, and restricted Docker runs.
132+
That sample is used in CI to validate Java dynamic dedup for JDK 8, 17, and 21 across native, classpath, Docker, distroless, and restricted Docker runs.

keploy-sdk/pom.xml

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
<parent>
88
<artifactId>java-sdk</artifactId>
99
<groupId>io.keploy</groupId>
10-
<version>1.0.0-SNAPSHOT</version>
10+
<version>2.0.0</version>
1111
</parent>
1212

1313
<artifactId>keploy-sdk</artifactId>
14-
<version>0.0.1-SNAPSHOT</version>
14+
<version>2.0.0</version>
1515
<name>Keploy Java Coverage Agent</name>
1616
<description>Java dynamic dedup coverage agent for Keploy Enterprise</description>
1717
<url>https://github.com/keploy/java-sdk</url>
@@ -78,6 +78,48 @@
7878

7979
<build>
8080
<plugins>
81+
<plugin>
82+
<groupId>org.apache.maven.plugins</groupId>
83+
<artifactId>maven-shade-plugin</artifactId>
84+
<version>3.5.3</version>
85+
<executions>
86+
<execution>
87+
<id>shade-java-agent</id>
88+
<phase>package</phase>
89+
<goals>
90+
<goal>shade</goal>
91+
</goals>
92+
<configuration>
93+
<createDependencyReducedPom>false</createDependencyReducedPom>
94+
<transformers>
95+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
96+
<manifestEntries>
97+
<Premain-Class>io.keploy.dedup.KeployDedupAgent</Premain-Class>
98+
<Agent-Class>io.keploy.dedup.KeployDedupAgent</Agent-Class>
99+
<Can-Redefine-Classes>false</Can-Redefine-Classes>
100+
<Can-Retransform-Classes>false</Can-Retransform-Classes>
101+
<Implementation-Title>${project.name}</Implementation-Title>
102+
<Implementation-Version>${project.version}</Implementation-Version>
103+
<Automatic-Module-Name>io.keploy.sdk</Automatic-Module-Name>
104+
</manifestEntries>
105+
</transformer>
106+
</transformers>
107+
<filters>
108+
<filter>
109+
<artifact>*:*</artifact>
110+
<excludes>
111+
<exclude>META-INF/*.SF</exclude>
112+
<exclude>META-INF/*.DSA</exclude>
113+
<exclude>META-INF/*.RSA</exclude>
114+
<exclude>module-info.class</exclude>
115+
<exclude>META-INF/versions/*/module-info.class</exclude>
116+
</excludes>
117+
</filter>
118+
</filters>
119+
</configuration>
120+
</execution>
121+
</executions>
122+
</plugin>
81123
<plugin>
82124
<groupId>org.apache.maven.plugins</groupId>
83125
<artifactId>maven-javadoc-plugin</artifactId>

0 commit comments

Comments
 (0)