James Hope
James Hope

Reputation: 43

Unable to build fat jar with dependencies with maven and bitbucket

What we are trying to do We are attempting to build and deploy a fat jar file (i.e. with all dependencies) using maven and scp all via a bitbucket pipeline but we are getting java.lang.NoClassDefFoundError: okhttp3/OkHttpClient.

What is the underlying java plugin supposed to be doing The jar file is a plugin for neo4j which is triggered when a change is made to the database. The plugin creates a json with various database properties, prepares these in json and sends them to another service on the same server using the OkHttpClient.

It's not a permissions issue We run a script on the bitbucket pipeline to ensure that permissions on the jar file are correct.

It's not an endpoint issue We have successfully tested the endpoint to which the OkHttpClient is referring with postman. Both services are running on the same docker-network so there should be no issue with port or http access.

Output in the neo4j logs We restart neo4j after a successful deployment and we see that the plugin has been successfully registered. We see that the json is prepared correctly however the plugin fails with the following error:

2020-12-05 16:43:30.121+0000 INFO  [o.n.s.AbstractNeoWebServer$ServerComponentsLifecycleAdapter] Web server started.
2020-12-05 16:43:37.318+0000 INFO  [c.n.k.i.p.PageCacheWarmer] [london/a225b7b2] Page cache warmup completed. 104622 pages loaded. Duration: 10s 389ms. 10.07 pages/ms
2020-12-05 16:44:10.434+0000 INFO  [c.i.n.t.MyTransactionEventListener] [london/a225b7b2] createJsonBody: json: [{"id":15591428}]
2020-12-05 16:44:10.435+0000 INFO  [c.i.n.t.MyTransactionEventListener] [london/a225b7b2] createJsonBody: json: [{"id":15591428}]
2020-12-05 16:44:10.507+0000 INFO  [c.i.n.t.MyTransactionEventListener] [london/a225b7b2] sendJsonToApi: json: [{"id":15591428}]
2020-12-05 16:44:10.514+0000 ERROR [o.n.b.r.s.i.ErrorReporter] Client triggered an unexpected error [Neo.DatabaseError.General.UnknownError]: okhttp3/OkHttpClient, reference 9a0e0b9c-43ae-4ef5-8fe8-b2bdebba1fd6.
2020-12-05 16:44:10.514+0000 ERROR [o.n.b.r.s.i.ErrorReporter] Client triggered an unexpected error [Neo.DatabaseError.General.UnknownError]: okhttp3/OkHttpClient, reference 9a0e0b9c-43ae-4ef5-8fe8-b2bdebba1fd6.
**java.lang.NoClassDefFoundError: okhttp3/OkHttpClient**
    at com.ikwattro.neo4j.tx.MyTransactionEventListener.sendJsonToApi(MyTransactionEventListener.java:77) ~[neo4j-tx-listener-1.0-SNAPSHOT.jar:?]
    at com.ikwattro.neo4j.tx.MyTransactionEventListener.afterCommit(MyTransactionEventListener.java:40) ~[neo4j-tx-listener-1.0-SNAPSHOT.jar:?]
    at com.ikwattro.neo4j.tx.MyTransactionEventListener.afterCommit(MyTransactionEventListener.java:22) ~[neo4j-tx-listener-1.0-SNAPSHOT.jar:?]
    at org.neo4j.kernel.internal.event.DatabaseTransactionEventListeners.afterCommit(DatabaseTransactionEventListeners.java:99) ~[neo4j-kernel-4.2.0.jar:4.2.0]
    at org.neo4j.kernel.impl.api.KernelTransactionImplementation.afterCommit(KernelTransactionImplementation.java:978) ~[neo4j-kernel-4.2.0.jar:4.2.0]

What we think the issue is This seems to be suggest to us that the jar is not built by maven with dependencies.

We are not sure on how to resolve.

Further information.

The java file / transaction handler is as follows:

public class MyTransactionEventListener extends TransactionEventListenerAdapter<Void> {

    private JSONArray json;
    private final LogService logsvc;

    public MyTransactionEventListener(GraphDatabaseService graphDatabaseService, LogService logsvc) {
        this.logsvc = logsvc;
    }

    @Override
    public Void beforeCommit(TransactionData data, Transaction transaction, GraphDatabaseService databaseService)
            throws Exception {
        createJsonBody(data);
        return null;
    }

    @Override
    public void afterCommit(TransactionData td, Void state, GraphDatabaseService db) {
        sendJsonToApi();
        resetJson();
    }

    @Override
    public void afterRollback(TransactionData data, Void state, GraphDatabaseService databaseService) {
        resetJson();
    }

    void resetJson() {
        this.json = null;
    }

    void createJsonBody(TransactionData td) {
        JSONArray json = new JSONArray();
        Iterable<Node> nodes = td.createdNodes();
        for (Node node : nodes) {
            JSONObject nodeJson = new JSONObject();
            long id = node.getId();
            try {
                nodeJson.put("id", id);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            json.put(nodeJson);
        }

        logsvc.getUserLog(MyTransactionEventListener.class).info("createJsonBody: json: " + json.toString());
        this.json = json;
    }

    void sendJsonToApi() {
        logsvc.getUserLog(MyTransactionEventListener.class).info("sendJsonToApi: json: " + json.toString());
        if (this.json == null)
            return;

        try {
            OkHttpClient client = new OkHttpClient().newBuilder().build();
            RequestBody body = RequestBody.create(json.toString().getBytes("utf-8"));
            Request request = new Request.Builder().url(ENDPOINT).method("POST", body)
                    .addHeader("Content-Type", "application/json").build();

            Response response = client.newCall(request).execute();
            
            logsvc.getUserLog(MyTransactionEventListener.class).info("sendJsonToApi: data should be sent");
            logsvc.getUserLog(MyTransactionEventListener.class).info("sendJsonToApi: response: " + response.toString());
        } catch (Exception e) {
            logsvc.getUserLog(MyTransactionEventListener.class).error("sendJsonToApi: Exception: " + e.toString());
        }
    }
}

The pipeline looks as follows:

image: maven:3.6.3

pipelines:
  default:
    - step:
        name: Build
        caches:
          - maven
        script: 
          - mvn clean compile assembly:single
          - mvn -B install
        artifacts:
          - 'target/neo4j-tx-listener-1.0-SNAPSHOT.jar'
  
    - step:
        name: Deploy-File
        deployment: production
        script:        
          - pipe: atlassian/scp-deploy:0.3.3
            variables:
              USER: $USER
              SERVER: $SERVER
              REMOTE_PATH: '/mnt/volume_lon1_01/neo4j/plugins'
              LOCAL_PATH: '${BITBUCKET_CLONE_DIR}/target/*'
          - pipe: atlassian/ssh-run:0.1.3
            variables:
              SSH_USER: $USER
              SERVER: $SERVER
              COMMAND: 'chmod 744 /mnt/volume_lon1_01/neo4j/plugins/neo4j-tx-listener-1.0-SNAPSHOT.jar'

The POM file is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ikwattro</groupId>
    <artifactId>neo4j-tx-listener</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <neo4j.version>4.2.1</neo4j.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j</artifactId>
            <version>${neo4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-kernel</artifactId>
            <version>${neo4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-logging</artifactId>
            <version>${neo4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-kernel</artifactId>
            <type>test-jar</type>
            <version>${neo4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jettison</groupId>
            <artifactId>jettison</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpasyncclient</artifactId>
            <version>4.1.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.5.13</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.10.0-RC1</version>
        </dependency>
    </dependencies>

    <build>

        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>

            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>                        <!-- this is used for inheritance merges -->
                        <phase>package</phase>                        <!-- bind to the packaging phase -->
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>



        </plugins>
    </build>


</project>

Any help would be most appreciated.

Upvotes: 0

Views: 549

Answers (1)

James Hope
James Hope

Reputation: 43

Issue resolved.

We needed to

  1. Copy the -jar-with-dependencies from the maven build step. We were copying the thin jar.

  2. Change the POM file as follows as per the neo4j instructions for custom plugins with for the dependencies already provided by neo4j.

Upvotes: 1

Related Questions