add JMH an existing spring boot project - spring-boot

I have tried multiple tutorials to make a poc using jmh inside my test package but always faced: No matching benchmarks. Miss-spelled regexp.
My latest code:
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.35</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.35</version>
</dependency>
I downloaded 'JMH Java Microbenchmark Harness' plugin ( I tried also JMHack)
created these two classes
public class TestBenchmark
{
#Benchmark
public void init() {
// Do nothing
}
}
and
public class BenchmarkRunner {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
}
And it's not working,
I will list couple of articles I already tried
from stackoverflow
This tutorial
medium article
I think I must create a new project but It would be great if I could apply it to an existing project

Once I did simple integration of JMH with Spring Boot, you can find an example in https://github.com/stsypanov/spring-boot-benchmark

Related

Using DynamoDBEnhancedAsyncClient to scan and fetch futureObject

I am trying to use v2 library to persist & retrieve data in non-blocking manner.
Put method of DynamoDBEnhancedAsyncClient returns CompletableFuture object but scan and query methods return PagePublisher object - that tends to tell me that this is a blocking call. Can someone please help me understand/fix this. I want to implement end-to-end non-blocking calls. I tried with DynamoAsyncClient and that works perfect but I want to get rid of manually mapping of objects using DynamoDBEnhancedAsyncClient*, but I see no method that returns CompletableFutures.
Here is my code block
DynamoDbAsyncTable<User> asyncTable = dynamoDBEnhancedAsyncClient.table("userTable", TableSchema.fromBeab(User.class));
Map<String, AttribiuteValue> expVal = new HashMap();
expVal.put(":val", AttributeValue.builder().n(String.valueOf(userId)).build());
Expression exp = Expression.builder().expression("userId = :val").expressionValues(expVal).build();
ScanEnhancedRequest req = ScanEnhancedRequest.builder().filterExpression(exp).build();
PagePublisher<User> pagePublisher = asyncTable.scan(req);
Dependencies I used
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactid>
<version>2.10.76</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb-enhanced</artifactid>
<version>2.12.0</version>
</dependency>
AWS SDK v2 leverages reactive streams to build its asynchronous functions.
PagePublisher<T> won't make your call blocking, this class implements the Publisher(doc) interface which allows you to subscribe on it.
Option1
According to your question which you would like to transfer Publisher to CompletableFuture, here is a rough example of how to do it:
var publisher = asyncTable.scan(req);
var future = new CompletableFuture<Page<User>>();
publisher.subscribe(
new Subscriber<>() {
#Override
public void onSubscribe(Subscription s) {
s.request(1);
}
#Override
public void onNext(Page<User> userPage) {
future.complete(userPage);
}
#Override
public void onError(Throwable t) {
future.completeExceptionally(t);
}
#Override
public void onComplete() {
future.complete(null);
}
});
var result = future.join();
Option2 (Recommended)
However, I saw you tagged this question with spring-boot and you mention that you want to implement nonblocking end to end calls.
I highly recommend you to integrate Spring Webflux with AWS SDK v2, which makes you to create a nonblocking/reactive web service easier.
By adopting Spring Webflux, you can integrate your code like:
Mono.from(asyncTable.scan(req))
which makes the code cleaner and simpler.

Spring boot and Swagger url and startup questions

I come from programming in c# and now I have to create a couple of Rest Apis in Spring Boot.
Everything is working ok and I can show the API in Swagger with springfox-swagger-ui
But I have two questions that I could not find in Internet
Is there any way to show the url ui in the console app with server, port, etc?
Is there any way to open the swagger url everytime I run the app in the localhost?
Thanks
Spring boot version
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
I know it's not the question you're asking, but springfox is currently having issues with newer versions of spring. The spring version you're using is still working but as of 2.6 there are bugs, and it looks like the project is not well maintained. Since you're at the beginning of the project, switching is not too hard. You could move to springdocs for example (for migration: https://springdoc.org/#migrating-from-springfox).
With respect to opening a url, there are some good solutions mentioned here: How to open the default webbrowser using java . You could make your swagger url a property and have swagger configure it accordingly, then you can reuse the property to call the url on run-time. If you want to differentiate between environments I'd suggest use profiles. Only open the url in the browser if you start the app on dev environment, and not on prod is then specified by using #Profile("dev"). Create a commandline/application runner with the profile annotation (https://www.tutorialspoint.com/spring_boot/spring_boot_runners.htm), and call the url from there.
That said, combining it gives:
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
#Profile("dev")
#Component
public class SwaggerRunner implements ApplicationRunner {
#Value("${springdoc.swagger-ui.path}")
private String swaggerPath;
#Override
public void run(ApplicationArguments args) throws Exception {
log("\nWelcome to Multi Brow Pop.\nThis aims to popup a browsers in multiple operating systems.\nGood luck!\n");
final String swaggerUrl = "http://localhost:8000/" + swaggerPath;
log("We're going to this page: " + swaggerUrl);
String myOS = System.getProperty("os.name").toLowerCase();
log("(Your operating system is: " + myOS + ")\n");
try {
if (Desktop.isDesktopSupported()) { // Probably Windows
log(" -- Going with Desktop.browse ...");
Desktop desktop = Desktop.getDesktop();
desktop.browse(new URI(swaggerUrl));
} else { // Definitely Non-windows
Runtime runtime = Runtime.getRuntime();
if (myOS.contains("mac")) { // Apples
log(" -- Going on Apple with 'open'...");
runtime.exec("open " + swaggerUrl);
} else if (myOS.contains("nix") || myOS.contains("nux")) { // Linux flavours
log(" -- Going on Linux with 'xdg-open'...");
runtime.exec("xdg-open " + swaggerUrl);
} else
log("I was unable/unwilling to launch a browser in your OS :( #SadFace");
}
log("\nThings have finished.\nI hope you're OK.");
} catch (IOException | URISyntaxException eek) {
log("**Stuff wrongly: " + eek.getMessage());
}
}
private static void log(String log) {
System.out.println(log);
}
}
put springdoc.swagger-ui.path=/custom/path in your application.properties to change the path to your swagger-ui

Share application.properties files in different project

Below showing the project structure
Core Project
|-config project
|
|-Service project
After building the core project we get Service.jar file.
While running the service.jar am passing spring.config.additional.location as command line argument.
java -jar Service-1.0.jar --spring.config.additional-location=C:/Users/Administrator/Desktop/Springboot/
above spring.config.additional.location path having application.property file and some xml files.
I can able to read application property file in service project ,following logic
Application.propertes
external.config=C:/Users/Administrator/Desktop/Springboot/config/
Mian Class
#ImportResource(locations = {
"${external.config}"+"/spring/service-config.xml",
"${external.config}"+"/spring/datasource-config.xml"
})
public class ServiceMain {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ServiceMain.class)
.build()
.run(args);
for (String name : applicationContext.getBeanDefinitionNames()) {
}
}
}
Similar kind of logic applied in config project is given below,its not working
#Configuration
public class ConfigurationFactory
{
#Value("${external.config}")
public String extConfPath;
public String REQ_CONF = extConfPath+"/Configuration.xml";
public static final String FILTER_XML_CONF = extConfPath+"/DocFilter.xml";
}
Is there any better way to do this? How can i read external application.properties in config project
Do we have any better way to do this in spring boot
As you are cleary developing a distributed web system the best practice is to used externalised configuration used by your different services allowing you to update settings without redeployment. Take a look at Spring Cloud Config

WebDriverManager for PhantomJSDriver not working

I cannot get WebDriverManager to work. I would like to use PhantomJSDriver without having to set a system property like this:
System.setProperty("phantomjs.binary.path", "E:/phantomjs-2.1.1-windows/bin/phantomjs.exe");
I have these dependencies in my pom.xml:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>1.5.1</version>
</dependency>
This is my code/test:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class TestA {
WebDriver driver;
#BeforeClass
public static void setupClass() {
PhantomJsDriverManager.getInstance().setup();
}
#Before
public void setUp() {
driver = new PhantomJSDriver();
}
#Test
public void test() {
driver.get("https://www.google.de/");
System.out.println(driver.getTitle());
assertEquals("Google", driver.getTitle());
}
}
The test fails:
org.junit.ComparisonFailure: expected:<[Google]> but was:<[]>
Does anybody know what I am doing wrong? Thanks in advance!
UPDATE: Now I have another problem. Before using the webdrivermanager I had this:
DesiredCapabilities dc = DesiredCapabilities.phantomjs();
dc.setJavascriptEnabled(true);
dc.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS,
new String[] { "--web-security=no", "--ignore-ssl-errors=yes" });
System.setProperty("phantomjs.binary.path", "E:/phantomjs-2.1.1-windows/bin/phantomjs.exe");
WebDriver driver = new PhantomJSDriver(dc);
Now, when I delete the line with System.setProperty(...), it is not working anymore. Thanks for helping.
Looks like your making the assertion to early, so the page is not loaded when you call getTitle() on it. What does your println print out?
Try adding a wait to to your test, if you know the page title should be "Google" then why not wait for that to be true before doing any further assertions? When the page title is equal to what your expecting you can be reasonably confident the page is loaded. Try this:
public Boolean waitForPageIsLoaded(String title) {
return new WebDriverWait(driver, 10).until(ExpectedConditions.titleIs(title));
}

Invoke Struts Action Test from within a web app (JSF managed bean): TestCase.fname cannot be null

I have a Junit 3.8 test of a Struts 2 action that runs with no problems from my workspace (from eclipse: right click > run as > junit test).
For this, I use two plugins:
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-junit-plugin</artifactId>
<version>2.1.8</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.1.8</version>
</dependency>
Here is the test class:
package com.myapp.user.my;
import org.apache.struts2.StrutsSpringTestCase;
import com.myapp.user.action.UserAction;
import com.opensymphony.xwork2.ActionProxy;
public class TestAccountActionUsingStrutsTestCase extends StrutsSpringTestCase {
public void testUserNameErrorMessage() throws Exception {
request.setParameter("userBean.userName", "Bruc");
request.setParameter("userBean.password", "test");
ActionProxy proxy = getActionProxy("/userAction");
UserAction userAction = (UserAction) proxy.getAction();
proxy.execute();
assertTrue("Problem There were no errors present in fieldErrors but there should have been one error present", userAction.getFieldErrors().size() == 1);
assertTrue("Problem field user.userName not present in fieldErrors but it should have been",
userAction.getFieldErrors().containsKey("userBean.userName") );
System.out.println("Finish 1 test.");
}
}
Next, I try to invoke this test, this time from within a web application (a JSF managed bean).
Here is my code for trying to do that (I'm calling the following runTest() method from a managed bean):
import java.util.List;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import com.myapp.user.my.TestAccountActionUsingStrutsTestCase;
public class CallStrutsActionExecuteThruTest {
public void runTest(){
System.out.println("CallStrutsActionExecuteThruTest.runTest() is executed.");
TestAccountActionUsingStrutsTestCase test = new TestAccountActionUsingStrutsTestCase();
JUnitCore jUnitCore = new JUnitCore();
Result result = jUnitCore.run(test);
List<Failure> list = result.getFailures();
for (Failure failure : list) {
System.out.println(failure.getMessage());
}
System.out.println("Test done!");
}
}
When I access the managed bean, I can see that runTest() is called. The first output CallStrutsActionExecuteThruTest.runTest() is executed. is printed to console. Strangely, the next outputs are not printed to console, although the debugger shows me they are executed.
Also, result.getFailures() returns a list with one element. As I said, its failure.getMessage() for some reason is not printed to console, but when I watch it in the debugger its value is TestCase.fname cannot be null.
* Even when I have only one method in my test class:
public void testTrue() throws Exception {
System.out.println("inside testTrue().");
assertTrue(true);
}
I still get the same results.
My questions are,
If I want to run the Struts action test from a JSF managed bean, am I using the Junit API correctly?
Why weren't the outputs that followed the first one printed to console?
How do I set TestCase.fname with a value? First I don't see a method in my test class to set this value. Second, from my understanding, fanme is the name of the test method in the test class that I want to call; and jUnitCore.run(test) should call all the test methods in the test class test, so how can I specify all these methods with only one fname parameter?
Download - you can download my project here. I use Maven, Eclipse, and deploy on Jboss 7.
I access the JSF managed bean by: http://localhost:8080/Struts2WithSpringDIIntegrationExampleJunitFromUI-1.0-SNAPSHOT/xhtml/hello.jsf
Struts2 tests don't work with raw parameters for some reason. Use parameterMap instead.
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
parameterMap.put("userBean.userName", new String[]{"Bruc"});
parameterMap.put("userBean.password", new String[]{"test"});
StrutsMockHttpServletRequest request = new StrutsMockHttpServletRequest();
request.setupGetServletPath("/userAction");
request.setParameterMap(parameterMap);

Resources