我是 Maven 新手,正在努力寻找提出这个问题的正确方法(因为我怀疑这个问题是 DynamoDBLocal 特有的)。
我正在尝试使用带有 Grizzly servlet 的 Jersey 启动 REST 服务器,但由于我不知道如何指定 mainClass 而mvn exec:java
失败。对于我的单元测试,我使用内存中的 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 "帮助"):
<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. https://stackoverflow.com/questions/18107375/getting-skipping-jacoco-execution-due-to-missing-execution-data-file-upon-exec
2. https://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
3. https://stackoverflow.com/questions/23190107/cannot-use-jacoco-jvm-args-and-surefire-jvm-args-together-in-maven
-->
<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>
我已经尝试搜索如何/在何处添加 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);
}
}