exec-maven-plugin 使用 DynamoDBLocal 时如何在 pom.xml 中设置 mainClass

exec-maven-plugin how to set mainClass in pom.xml when using DynamoDBLocal

我是 Maven 的新手,正在努力寻找提出这个问题的正确方法(因为我怀疑这个问题是特定于 DynamoDBLocal 的)。

我正在尝试使用带有 Grizzly servlet 的 Jersey 启动 REST 服务器,但是 mvn exec:java 失败了,因为我不知道如何指定 mainClass。对于我的单元测试,我使用内存中的 DynamoDBLocal 来模拟数据库。我也 希望 在短期内使用 DynamoDBLocal 作为实际的数据库,而 运行 REST 服务器(只是在概念验证阶段)只是为了不花钱AWS,直到我准备好处理一些流量。

当 运行 mvn exec:java 时,出现以下故障:

$ mvn exec:java
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ my-app ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.436 s
[INFO] Finished at: 2019-03-17T16:49:52-07:00
[INFO] Final Memory: 14M/309M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java (default-cli) on project my-app: The parameters 'mainClass' for goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java are missing or invalid -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginParameterException

pom.xml (ctrl+f "HELP"):

<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>my-app</name>
    <url>http://maven.apache.org</url>

    <properties>
        <jacoco.threshold.class>1.00</jacoco.threshold.class>
        <jacoco.threshold.method>0.90</jacoco.threshold.method>
        <jacoco.threshold.instruction>0.80</jacoco.threshold.instruction>
        <jacoco.threshold.line>0.80</jacoco.threshold.line>
        <jacoco.threshold.branch>0.80</jacoco.threshold.branch>
        <jacoco.threshold.complexity>0.80</jacoco.threshold.complexity>

        <dependencies.jersey2.version>2.28</dependencies.jersey2.version>
    </properties>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12.4</version>
                <configuration>
                    <!--
                        Sqlite4java is needed by DynamoDB Local, but argLine is also needed by JaCoCo.
                        See JaCoCo help links:
                            1. 
                            2. https://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
                            3. 
                    -->
                    <argLine>-Dsqlite4java.library.path=${basedir}/lib/sqlite4java ${argLine}</argLine>
                </configuration>
            </plugin>

            <!--
                JaCoCo setup tutorial @ https://automationrhapsody.com/automated-code-coverage-of-unit-tests-with-jacoco-and-maven/
            -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.1</version>
                <configuration>
                    <excludes>
                        <exclude>**/config/*.class</exclude>
                        <exclude>**/exceptions/*.class</exclude>
                        <exclude>**/models/**/*.class</exclude>
                    </excludes>
                </configuration>
                <executions>
                    <!-- Prepares the property pointing to the JaCoCo runtime agent. -->
                    <execution>
                        <id>jacoco-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <!-- Create the index.html report file in target/site/ dir. -->
                    <execution>
                        <id>jacoco-report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                    <!-- Enforce code coverage -->
                    <execution>
                        <id>jacoco-check</id>
                        <phase>test</phase>
                        <goals>
                            <goal>check</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <rule>
                                    <element>BUNDLE</element>
                                    <limits>
                                        <limit>
                                            <counter>CLASS</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>${jacoco.threshold.class}</minimum>
                                        </limit>
                                        <limit>
                                            <counter>METHOD</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>${jacoco.threshold.method}</minimum>
                                        </limit>
                                        <limit>
                                            <counter>INSTRUCTION</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>${jacoco.threshold.instruction}</minimum>
                                        </limit>
                                        <limit>
                                            <counter>LINE</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>${jacoco.threshold.line}</minimum>
                                        </limit>
                                        <limit>
                                            <counter>BRANCH</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>${jacoco.threshold.branch}</minimum>
                                        </limit>
                                        <limit>
                                            <counter>COMPLEXITY</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>${jacoco.threshold.complexity}</minimum>
                                        </limit>
                                    </limits>
                                </rule>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.10.19</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.16</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-dynamodb -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-dynamodb</artifactId>
            <version>1.11.349</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>21.0</version>
        </dependency>

        <!-- https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html#DynamoDBLocal.Maven -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>DynamoDBLocal</artifactId>
            <version>1.11.119</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.codehaus.mojo/exec-maven-plugin -->
        <dependency>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!-- JAX-RS -->
        <!-- from https://howtodoinjava.com/jersey/jersey-2-hello-world-application-tutorial/ -->
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- Jersey with Grizzly servlet -->
        <!-- From https://jersey.github.io/documentation/latest/getting-started.html-->
        <!-- Benchmark from 2016 shows Grizzly is (neglibly) the best - https://menelic.com/2016/01/06/java-rest-api-benchmark-tomcat-vs-jetty-vs-grizzly-vs-undertow/ -->
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-grizzly2-http</artifactId>
            <version>${dependencies.jersey2.version}</version>
        </dependency>
        <dependency> <!-- Idk what this is? -->
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
            <version>${dependencies.jersey2.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305 -->
        <dependency>
            <groupId>com.google.code.findbugs</groupId>
            <artifactId>jsr305</artifactId>
            <version>3.0.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.tngtech.java/junit-dataprovider -->
        <dependency>
            <groupId>com.tngtech.java</groupId>
            <artifactId>junit-dataprovider</artifactId>
            <version>1.13.1</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <repositories>
        <!-- https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html#DynamoDBLocal.Maven -->
        <repository>
            <id>dynamodb-local-oregon</id>
            <name>DynamoDB Local Release Repository</name>
            <url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</url>
        </repository>
    </repositories>

    <profiles>
        <profile>
            <id>start-dynamodb-local</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <version>1.4.0</version>
                        <executions>
                            <execution>
                                <phase>initialize</phase>
                                <configuration>
                                    <executable>java</executable>
                                    <arguments>
                                        <argument>-cp</argument>
                                        <classpath/>
                                        <argument>-Dsqlite4java.library.path=${basedir}/target/dependencies</argument>
                                        <argument>com.amazonaws.services.dynamodbv2.local.main.ServerRunner</argument>
                                        <argument>-inMemory</argument>
                                        <argument>-port</argument>
                                        <argument>8000</argument>
                                    </arguments>

                                    <!-- HELP: Do I add mainClass here? -->
                                    <!-- <mainClass>com.pathto.mymainclass.Main</mainClass> -->

                                </configuration>
                                <goals>
                                    <goal>exec</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>

        <!-- HELP: Do I add mainClass within a new profile here? -->

</project>

我已经尝试在 SO 中搜索 how/where 来添加 mainClass,但我没有找到与我的 pom 足够相似的东西,我也无法理解 maven/pom 是如何工作的如何使这项工作。

我还应该补充:mvn package 在我的所有测试中 运行 都成功了,包括在端口 8080 上运行 Grizzly 服务器并从 RESTful 客户端连接到它的测试:

import java.net.URI;
import javax.ws.rs.client.ClientBuilder;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * Validate that server dependencies successfully run a server on our local port and we can connect to it via HTTP client.
 */
public class ServerTest {

    private static final String BASE_URI = "http://localhost:8080/rest/v1/";

    private HttpServer httpServer;

    @Before
    public void startServer() {
        ResourceConfig resourceConfig = new ResourceConfig().packages("com.pathto.mycontrollers");
        httpServer = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), resourceConfig);
    }

    @After
    public void stopServer() {
        httpServer.shutdownNow();
    }

    @Test
    public void test() {
        // There is a simple class com.pathto.mycontrollers.HealthController that just responds saying "healthy"
        String healthResponse = ClientBuilder.newClient()
                .target(BASE_URI)
                .path("health")
                .request()
                .get(String.class);

        Assert.assertEquals("healthy", healthResponse);
    }
}

@Fridge 老实说我不确定,因为我在这里还是个新手,但无论如何我都会把它留在这里:)

看看:run main class of Maven project