Spring boot mvc async execution - java

I'm trying to execute simplest async REST controller using java.util.concurrent.Callable:
#RequestMapping("/AsyncRequest")
public Callable asyncRequest() {
return () -> {
Thread.sleep(3000);
return "reply";
};
}
Then I run http://localhost/AsyncRequest two times in browser.
The first answer I get in 3 seconds, but the second just after 6 seconds.
It seems like that the requests processed not asynchronously.
Why this happen?

Spring Boot behavior really depends on version and configuration.
The following configuration and code works for me:
Starter
package com.stackoverflow.spring.boot.async;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Import;
#Import(WebConfig.class)
#SpringBootApplication
public class WebMain {
private final SpringApplication application;
public WebMain() {
final SpringApplicationBuilder applicationBuilder = new SpringApplicationBuilder(WebMain.class);
application = applicationBuilder.build();
}
public SpringApplication getApplication() { return application; }
public static void main(final String[] args) {
new WebMain().getApplication().run(args);
}
}
Configuration
package com.stackoverflow.spring.boot.async;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter implements EmbeddedServletContainerCustomizer
{
public void customize(final ConfigurableEmbeddedServletContainer container) {}
}
Controller
I've changed sleep time here to 6 second and added some payload into response.
package com.stackoverflow.spring.boot.async;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.concurrent.Callable;
#Controller
public class AsyncController {
#RequestMapping(path = "/AsyncRequest", method = RequestMethod.GET)
#ResponseBody
public Callable<String> asyncRequest() {
return () -> {
final long currentThread = Thread.currentThread().getId();
final Date requestProcessingStarted = new Date();
Thread.sleep(6000L);
final Date requestProcessingFinished = new Date();
return String.format(
"request: [threadId: %s, started: %s - finished: %s]"
, currentThread, requestProcessingStarted, requestProcessingFinished);
};
}
}
pom.xml
<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.stackoverflow.spring.boot</groupId>
<artifactId>async</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-boot.version>1.4.1.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<inherited>true</inherited>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Testing
java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
--
mvn spring-boot:run
...
--
# start following command from different consoles:
curl http://localhost:8080/AsyncRequest
Results
request: [threadId: 33, started: 15:50:28 - finished: 15:50:34]
request: [threadId: 35, started: 15:50:29 - finished: 15:50:35]
request: [threadId: 37, started: 15:50:30 - finished: 15:50:36]

Related

#EventListener spring boot fails to compile

Wrote my first Spring Boot app that count number of refreshes. I print to port 8080 "Hello World" + Counter.
Counter should increase at each user refresh and show on live the number of refreshes after the "Hello World" string.
For this goal I am using the #RestController and #EventListener interfaces.
When building my app, it fails on #EventListener import and interface call:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project backend: Compilation failure: Compilation failure:
[ERROR] /home/project/backend/src/main/java/com/iz/backend/myController.java:[9,58] error: cannot find symbol
[ERROR] package org.springframework.cloud.context.config.annotation
[ERROR] /home/project/backend/src/main/java/com/iz/backend/myController.java:[57,5] error: incompatible types: EventListener cannot be converted to Annotation
Class:
package com.iz.backend;
import org.springframework.stereotype.Controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.config.annotation.EventListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
#RefreshScope
#RestController //interface
public class myController {
static int counter = -1;
#RequestMapping("/")
public String helloWorld() {
try
{
return "Hello World " + counter;
}
catch (IOException e)
{
e.printStackTrace();
}
return "Failed to execute";
}
#EventListener
public void handleContextRefreshEvent(ContextRefreshedEvent event) {
counter += 1;
}
}
pom.xml file:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.iz</groupId>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>backend</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
MAVEN 3.6.3, JAVA 11
I suggest you to do the following:
Remove the try catch block (Exception 'java.io.IOException' is never thrown in the corresponding try block)
Optimize the imports (you have duplicate/ambigous imports)
Use something like an AtomicInteger as counter

JMockit on "main" code - not only in Test

Can anyone tell is it possible to use JMockit on production code? It's working when I run my code under Tests but when I try the same code from "main" I'm getting messages about bad initialization:
JMockit version 1.41:
Exception in thread "main" java.lang.ExceptionInInitializerError
at pac1.main.main(main.java:17)
Caused by: java.lang.IllegalStateException: JMockit didn't get initialized; please check jmockit.jar precedes junit.jar in the classpath
at mockit.internal.startup.Startup.verifyInitialization(Startup.java:117)
at mockit.MockUp.<clinit>(MockUp.java:56)
... 1 more
JMockit 1.42 and higher - requires the use of the "-javaagent" JVM initialization parameter:
Exception in thread "main" java.lang.ExceptionInInitializerError
at pac1.main.main(main.java:17)
Caused by: java.lang.IllegalStateException: JMockit didn't get initialized; please check the -javaagent JVM initialization parameter was used
at mockit.internal.startup.Startup.verifyInitialization(Startup.java:91)
at mockit.MockUp.<clinit>(MockUp.java:56)
... 1 more
This is working test code:
package pac1;
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import mockit.Mock;
import mockit.MockUp;
import org.junit.Test;
public class TestClass {
#Test
public void givenLocalDateTimeMock_whenNow_thenGetFixedLocalDateTime() {
Clock clock = Clock.fixed(Instant.parse("2014-12-22T10:15:30.00Z"), ZoneId.of("UTC"));
new MockUp<LocalDate>() {
#Mock
public LocalDate now() {
return LocalDate.now(clock);
}
};
System.out.println(LocalDate.now());
ClasInvokingSomeClass test = new ClasInvokingSomeClass();
test.runApp2();
}
}
This is not working "production" code:
package pac1;
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import mockit.Mock;
import mockit.MockUp;
public class main {
public static void main(String[] args) {
Clock clock = Clock.fixed(Instant.parse("2014-12-22T10:15:30.00Z"), ZoneId.of("UTC"));
new MockUp<LocalDate>() {
#Mock
public LocalDate now() {
return LocalDate.now(clock);
}
};
System.out.println(LocalDate.now());
ClasInvokingSomeClass test = new ClasInvokingSomeClass();
test.runApp2();
}
}
and pom file:
<?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.test</groupId>
<artifactId>test1</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}"/org/jmockit/jmockit/1.49/jmockit-1.49.jar
</argLine>
</configuration>
</plugin>
</plugins>
</build>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies -->
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.42</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
</dependencies>
</project>

Junit with maven program is not working

When i run this i am getting Initialization error and there is no console error.
I have attached my junit test code and pom.xml code. please help me with the solution. And its a Maven project.
Junit program:
import static org.junit.Assert.*;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.Select;
public class JunitTest {
#Test
public void test() {
// fail("Not yet implemented");
System.out.println("Junit code");
WebDriver driver = new ChromeDriver();
driver.get("https://www.amazon.in/");
Select s = new Select(driver.findElement(By.id("searchDropdownBox")));
s.selectByVisibleText("Books");
driver.findElement(By.id("twotabsearchtextbox")).sendKeys("harry potter");
}
}
Pom.xml:
<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.testmaven</groupId>
<artifactId>mavenDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<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.seleniumhq.selenium/selenium-server -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>3.5.2</version>
</dependency>
</dependencies>
</project>
You need to define a build phase in POM for doing the compilation of integrated unit tests.
add this code snippet in pom.xml for running the test classes.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
You can find more information on:
http://maven.apache.org/surefire/maven-failsafe-plugin/usage.html

High latency with Spring multipart file

I'm currently working on a Spring-boot project in which I have to send files (one at a time) through a REST Web Service to a server, which sends it to a Cassandra cluster.
This part works, but my problem appeared when I began to do stress tests (with Gatling) on my project.
Here it is :
- When I tested my work without sending files, I had latency ~10-15 ms ;
- When I tested my work sending a file in the body of the request, I had latency ~10-15 ms too (maybe a little higher by 5 or 10 ms, I don't remember);
- BUT, and my problem shows up here, when I tested the Web Service by sending files with an input, and getting it with MultipartFile, the latency was very variable, from 10 ms for the fastest requests, to 12000ms (!!) for the longest.
I tried to set the files in memory limit to 1Go (it was originaly ~10ko), but it didn't change anything.
I don't get any error while executing the tests, it's just very long...
Plus, this project is being made to modernize the existing webservice, which runs as a JAX-WS, with WSDL and all. The team working on the old project (we are switching from a DBMS to an other) has response times of ~10 in mean !
Here's my conf (this is for a POC, the machines are cheap) :
- Web server : Wildfly 9-0-1.FINAL out of the box, on CentOS Server 7.1;
- Stress tests machine : Gatling 2.1.7, on the same CentOS version as Wildfly, but on an other machine;
- An 8 nodes Cassandra cluster.
Here is my pom (without company's secrets | concerning the spring-boot dependency, it's not my project's parent, it already has one):
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>1.3.0.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>oss-jfrog-artifactory</id>
<name>oss-jfrog-artifactory-releases</name>
<url>http://oss.jfrog.org/artifactory/oss-release-local</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</>
</pluginRepository>
</pluginRepositories>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
StartApp.java:
package foo.bar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
#SpringBootApplication
#EnableAutoConfiguration(exclude = MultipartAutoConfiguration.class)
public class StartApp extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(StartApp.class);
}
public static void main(String[] args) {
SpringApplication.run(StartApp.class, args);
}
#Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxInMemorySize(1024 * 1024 * 1024); // 1Go
return multipartResolver;
}
}
WS.java (only the relevant function) :
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import service.DaoException;
import service.ErrCode;
import service.IService;
...
#Inject IService service;
...
#RequestMapping(path = "/insert/{foo}/{bar}", method = POST)
public ResponseEntity<Void> insert(#PathVariable String foo,
#PathVariable String bar,
#RequestParam MultipartFile document) {
HttpStatus httpCode = HttpStatus.CREATED;
try (InputStream is = document.getInputStream()) {
service.insert(foo, bar, is);
} catch (DaoException e) {
logger.error("Problème lors de l'insertion du document : "
+ e.getMessage());
httpCode = handleError(e.getCode());
} catch (IOException e1) {
logger.error("Problème lors du traitement du document envoyé : "
+ e1.getMessage());
httpCode = handleError(ErrCode.PB_TECHNIQUE);
}
return ResponseEntity.status(httpCode).build();
}
Simulation.scala :
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.Path
import java.util.Base64
import java.io.File
import java.lang.String
class RestSimulation1 extends Simulation {
val DEBIT = 30 //Clients per second
val DUREE = 300 //Duration
val httpConf = http
.baseURL("http://myserver:8080") // Here is the root for all relative urls
.acceptHeader("text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8") // Here are the common headers
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
//Feeders creation
val feeder = csv("9k_rest.csv").queue
object Insert {
val insert = feed(feeder)
.exec(http("insertion")
.post("/webservice/ws/insert/${fooo}/${bar}")
.formUpload("document", "rest_insert_${format}.txt")
.check(status.is(201)))
}
val scn = scenario("").exec(Insert.insert)
setUp(scn.inject( constantUsersPerSec(DEBIT) during(DUREE seconds))).protocols(httpConf)
}
What do I do wrong ?
Thank you for your help :)

Accessing compiled resources in a Pax Exam contained test

I've been trying to run a JMH benchmark test in an OSGI container created with Pax Exam (similarly to how it's described in this SO answer, but with Pax Exam thrown into the mix as well). But am having some problems getting the JMH generated resource files created during the compilation to load.
After the tests have been compiled, the following can be found in the target/test-classes directory:
$ ls -l target/test-classes/META-INF
BenchmarkList CompilerHints
In a test I use some code (that I cannot change) that (effectively) looks for the file like so:
getClass().getClassLoader().getResources("META-INF/BenchmarkList");
Running this fails (returns 0 results) and I get the following error:
java.lang.RuntimeException: ERROR: Unable to find the resource: /META-INF/BenchmarkList
at org.openjdk.jmh.runner.AbstractResourceReader.getReaders(AbstractResourceReader.java:96)
at org.openjdk.jmh.runner.BenchmarkList.find(BenchmarkList.java:104)
at org.openjdk.jmh.runner.Runner.internalRun(Runner.java:228)
at org.openjdk.jmh.runner.Runner.run(Runner.java:178)
at com.company.project.performance.MyBenchmarkTest.launchBenchmark(MyBenchmarkTest.java:145)
I've tried creating a bundle containing the file, like so:
streamBundle(bundle()
.add("META-INF/BenchmarkList", new FileInputStream("target/test-classes/META-INF/BenchmarkList"))
.build()),
Which does create a JAR with the following contents:
META-INF/MANIFEST.MF
META-INF/
META-INF/BenchmarkList
But the problem persists. How could I make the resource file available for JMH?
An MCVE:
pom.xml:
<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.company.project</groupId>
<artifactId>performance</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>MCVE for JMH+PaxExam issue</name>
<prerequisites>
<maven>3.0</maven>
</prerequisites>
<properties>
<apache-servicemix.version>5.4.0</apache-servicemix.version>
<junit.version>4.11</junit.version>
<jmh.version>1.10.1</jmh.version>
<pax-exam.version>4.4.0</pax-exam.version>
<tinybundles.version>2.1.0</tinybundles.version>
<maven-sunfire-report-plugin.version>2.18.1</maven-sunfire-report-plugin.version>
<maven-depends-plugin.version>1.2</maven-depends-plugin.version>
<maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>
<javac.target>1.7</javac.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam</artifactId>
<version>${pax-exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-karaf</artifactId>
<version>${pax-exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>${pax-exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.servicemix</groupId>
<artifactId>apache-servicemix</artifactId>
<version>${apache-servicemix.version}</version>
<scope>test</scope>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.ops4j.pax.tinybundles</groupId>
<artifactId>tinybundles</artifactId>
<version>${tinybundles.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
<version>${maven-depends-plugin.version}</version>
<executions>
<execution>
<id>generate-depends-file</id>
<goals>
<goal>generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-sunfire-report-plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>${maven-sunfire-report-plugin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${javac.target}</source>
<target>${javac.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
src/test/java/com/company/project/performance/MyBenchmarkTest.java:
package com.company.project.performance;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.maven;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.streamBundle;
import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
import static org.ops4j.pax.tinybundles.core.TinyBundles.bundle;
import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
import java.io.File;
import java.io.FileInputStream;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.MavenUtils;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.options.MavenArtifactUrlReference;
#RunWith(PaxExam.class)
public class MyBenchmarkTest
{
public static final String BENCHMARK_LIST = "META-INF/BenchmarkList";
#Benchmark
public void measureThroughput() throws InterruptedException
{
TimeUnit.MILLISECONDS.sleep(100);
}
#Configuration
public Option[] config() throws Exception
{
String karafVersion = MavenUtils.getArtifactVersion("org.apache.karaf", "apache-karaf");
MavenArtifactUrlReference servicemixUrl = maven()
.groupId("org.apache.servicemix")
.artifactId("apache-servicemix")
.versionAsInProject()
.type("zip");
return options(karafDistributionConfiguration()
.frameworkUrl(servicemixUrl)
.useDeployFolder(false)
.karafVersion(karafVersion)
.unpackDirectory(new File("target/exam")),
keepRuntimeFolder(),
junitBundles(),
wrappedBundle(maven("org.openjdk.jmh", "jmh-core")),
streamBundle(bundle()
.add(BENCHMARK_LIST, new FileInputStream("target/test-classes/" + BENCHMARK_LIST))
.build(withBnd())));
}
#Test
public void launchBenchmark() throws Exception
{
Options opts = new OptionsBuilder()
.include("com.company.project.performance.*")
.warmupIterations(1)
.forks(1)
.build();
new Runner(opts).run();
}
}
The issue is clearly an import export issue.
As your test which is using your meta data, isn't aware of those extra data.
The bundle you generated with the streamBundle, needs to add an extra header information actually exporting those extra data.
streamBundle(bundle()
.add(BENCHMARK_LIST, new FileInputStream("target/test-classes/" + BENCHMARK_LIST))
.set(Constants.EXPORT_PACKAGE, BENCHMARK_LIST)
and in your test you'll need to make sure you are actually importing it.
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
//make sure the needed imports are there.
probe.setHeader(Constants.IMPORT_PACKAGE, "*,"+BENCHMARK_LIST);
return probe;
}
on the other hand it might just be a lot better to actually try to add those extra data into the test-bundle (your test class is generated into a bundle on the fly)
Therefore the following should be added to the configuration
.metaInfResource(BENCHMARK_LIST)

Categories