I am trying to generate the wrapper on fly using web3j and invoking a method on the generated class using reflection. But I am getting classNotFound exception on the first try. (When I stop the server and re-run, it works because the class was already present)
Does java support generating class on fly (when server is running) ?
private void createContractClass(String contractFileNameWithoutExtension) {
try {
String command = "web3j solidity generate -b " +
contractLocation+contractFileNameWithoutExtension+".bin -a "+contractLocation+contractFileNameWithoutExtension+".abi" +
" -o "+sourceCodeLocation+" -p generated";
LOG.info("Executing {}", command);
Process p = Runtime.getRuntime().exec(command);
int exitCode = p.waitFor();
if(exitCode != 0) {
LOG.error("Error {}", p.getOutputStream());
}
} catch(IOException | InterruptedException ex) {
ex.printStackTrace();
throw new FormatException(ValidationMessages.FAILED_TO_DEPLOY_CONTRACT);
}
}
private String invokeDeployment(String password, String walletFileName, String contractFileName) {
try {
Credentials credentials = WalletUtils.loadCredentials(password, walletLocation + "/" + walletFileName);
Class classz = Class.forName("generated."+ StringUtils.capitalize(contractFileName));
Method method = classz.getDeclaredMethod("deploy", Web3j.class, Credentials.class, BigInteger.class, BigInteger.class);
RemoteCall<?> invoke = (RemoteCall<?>)method.invoke(classz, web3JClient.getClient(), credentials, DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT);
Contract contract = (Contract)invoke.send();
return contract.getContractAddress();
} catch (Exception e){
e.printStackTrace();
throw new FormatException(ValidationMessages.FAILED_TO_DEPLOY_CONTRACT);
}
}
It was because, the class was not loaded in the class path. Compile and load the class to the class path resolved the issue.
Related
I'm trying to use Moshi with GraalVM's native-image, and trying to get the reflection to work.
I have my class:
public class SimpleJson {
private String message;
public SimpleJson(String message) { this.message = message; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
}
and code
var simpleJsonJsonAdapter = moshi.adapter(SimpleJson.class);
var simpleJsonString = "{\"message\": \"hello there\"}";
var simpleJsonObj = simpleJsonJsonAdapter.fromJson(simpleJsonString);
var simpleJsonStringBack = simpleJsonJsonAdapter.toJson(simpleJsonObj);
System.out.println("Converting: " + simpleJsonString);
System.out.println("Simple json has message: " + simpleJsonObj.getMessage());
System.out.println("Simple message full json coming back is: " + simpleJsonStringBack);
which prints:
Converting: {"message": "hello there"}
Simple json has message: null
Simple message full json coming back is: {}
and this only works (by avoiding an exception with SimpleJson is instantiated reflectively but was never registered) with the following chunk of code, to get everything registered ready for reflection:
#AutomaticFeature
public class RuntimeReflectionRegistrationFeature implements Feature {
#Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
try {
// Enable the moshi adapters
var moshiPkgs = "com.squareup.moshi";
// Standard shared models
var pkgs = "my.models";
// Register moshi
new ClassGraph()
.enableClassInfo()
.acceptPackages(moshiPkgs)
.scan()
.getSubclasses(JsonAdapter.class.getName())
.forEach(
classInfo -> {
System.out.println("Building moshi adapter class info for " + classInfo);
registerMoshiAdapter(classInfo.loadClass());
});
// Register everything we've got
new ClassGraph()
.enableClassInfo() // Scan classes, methods, fields, annotations
.acceptPackages(pkgs) // Scan package(s) and subpackages
.scan()
.getAllClasses()
.forEach(
classInfo -> {
System.out.println("Building class info for " + classInfo);
registerGeneralClass(classInfo.loadClass());
});
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
private void registerMoshiAdapter(Class<?> classInfo) {
try {
RuntimeReflection.register(classInfo);
Arrays.stream(classInfo.getMethods()).forEach(RuntimeReflection::register);
ParameterizedType superclass = (ParameterizedType) classInfo.getGenericSuperclass();
// extends JsonAdapter<X>()
var valueType = Arrays.stream(superclass.getActualTypeArguments()).findFirst();
if (valueType.isPresent() && valueType.get() instanceof Class) {
Arrays.stream(((Class<?>) valueType.get()).getConstructors())
.forEach(RuntimeReflection::register);
}
RuntimeReflection.register(classInfo.getConstructor(Moshi.class));
} catch (RuntimeException | NoSuchMethodException name) {
// expected
}
}
private void registerGeneralClass(Class<?> classInfo) {
try {
RuntimeReflection.register(classInfo);
Arrays.stream(classInfo.getDeclaredMethods()).forEach(RuntimeReflection::register);
Arrays.stream(classInfo.getDeclaredConstructors()).forEach(RuntimeReflection::register);
} catch (RuntimeException name) {
// expected
}
}
}
(inspired by this issue, although I believe that's trying to address MoshiAdapters generated which is a Kotlin only thing).
So, Java doesn't complain about reflection (which it was previously trying to do, hence the error message mentioned), but Moshi isn't actually doing anything.
Does anyone have any suggestions on how to work around this?
Note, I did try the manual reflect-config.json approach with
[
{
"allDeclaredClasses": true,
"queryAllDeclaredConstructors": true,
"queryAllPublicConstructors": true,
"name": "my.models.SimpleJson",
"queryAllDeclaredMethods": true,
"queryAllPublicMethods": true,
"allPublicClasses": true
}
}
but this resulted in error around Runtime reflection is not supported for... - also not good!
The solution was simple in the end... the registration just needed
Arrays.stream(classInfo.getDeclaredFields()).forEach(RuntimeReflection::register);
adding.
I have implemented an event listener for Cucumber events:
public class AdccEventListener implements ConcurrentEventListener {
private static boolean stepFailed = false;
#Override
public void setEventPublisher(EventPublisher publisher) {
System.out.println("register handlers!!!");
publisher.registerHandlerFor(TestCaseStarted.class, this::scenarioStartedHandler);
publisher.registerHandlerFor(TestCaseFinished.class, this::scenarioFinishedHandler);
publisher.registerHandlerFor(TestStepStarted.class, this::stepStartedHandler);
publisher.registerHandlerFor(TestStepFinished.class, this::stepFinishedHandler);
}
private void scenarioStartedHandler(TestCaseStarted event) {
stepFailed = false;
}
private void scenarioFinishedHandler(TestCaseFinished event) {
BaseTestUtils.reportInfoMessage("Scenario finish name is: " + event.getTestCase().getName() + " end of Scenario statement!");
if (stepFailed) {
Result result = event.getResult();
setPrivateField(result, "status", Status.FAILED);
}
}
private void stepStartedHandler(TestStepStarted event) {
if (event.getTestStep() instanceof PickleStepTestStep) {
PickleStepTestStep testStep = (PickleStepTestStep) event.getTestStep();
BaseTestUtils.reportInfoMessage("step name is: " + testStep.getStep().getText() + " end of statement!");
ThreadLocalEvent.setStep(testStep);
}
}
private void stepFinishedHandler(TestStepFinished event) {
if (event.getTestStep() instanceof PickleStepTestStep) {
PickleStepTestStep testStep = (PickleStepTestStep) event.getTestStep();
Result result = event.getResult();
ThreadLocalEvent.setResult(result);
if (result.getStatus().equals(Status.FAILED)) {
if (!testStep.getStep().getKeyWord().startsWith("Given")) {
stepFailed = true;
setPrivateField(result, "status", Status.PASSED);
}
}
}
}
private void setPrivateField(Object subject, String fieldName, Object value) {
try {
Field f = subject.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(subject, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
i have declared the Event Listener as a plugin in the CucumberOptions of the RunTests class.
#CucumberOptions(plugin = {"pretty", "html:target/cucumber", "json:target/cucumber.json", "com.radware.bdd.AdccEventListener"},
glue = {"com.radware.tests"},
features = {"src/test/resources/Features"},
strict = true,
tags = {"#Functional"})
Now when i am executing tests on my local work station all is good. i am getting all events that were published in listener.
But, When the same project is executed on the docker container, listener does not get any events.
f. e. start Step, end Step events.
any idea what could cause it to not work under container?
Thank you.
Stas
I have found a problem.
When Maven tests were initiated from Jenkins or Docker container CucumberOptions arguments were passed. one of arguments was "--plugin". so my local definitions were overwritten.
Resolution is to add my custom plugin "com.radware.bdd.AdccEventListener" to the options passed through cli command.
I want to write junit test case for the below code with springJunitRunner.
the below piece of code is one service in a class.
#Component
#Path(/techStack)
public class TechStackResource {
#Autowired
private transient TechStackService techStackService;
#GET
#Path("/{id}")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response getTechStackById(final #PathParam("id") Integer technicalstackid) {
final TechStackResponse response = new TechStackResponse();
int statusCode = Constants.HTTP_STATUS_OK_200;
try {
TechStackModel techStackModel = techStackService.findObjectById(technicalstackid);
response.setGetTechStackDetails(GetTechStackDetails.newBuilder().technicalStack(techStackModel).build());
if (techStackModel == null) {
statusCode = Constants.HTTP_STATUS_ERROR_404;
}
} catch (EmptyResultDataAccessException erde) {
} catch (Exception e) {
LOGGER.error("Exception occured in TechStackResource.getTechStackById(technicalstackid) ", e);
throw new APMRestException(
"Exception while executing TechStackResource.getTechStackById(technicalstackid) ",
Constants.UNKNOW_ERROR, e);
}
return Response.status(statusCode).entity(response).build();
}
}
the configuration in web.xml for servlet is
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
Since you are using Jersey as well as Spring, you can use the SpringJunitRunner only to wire-up TechStackResource with its dependency TechStackService.
In order to test your REST handler method getTestStackById, you could go the POJO approach and invoke it directly. Alternatively, you can use Jersey's own MockWeb environment. To find out more about this, I recommend looking at the Jersey example sources, e.g. HelloWorld.
How do I launch a browser automatically after starting the spring boot application.Is there any listener method callback to check if the webapp has been deployed and is ready to serve the requests,so that when the browser is loaded , the user sees the index page and can start interacting with the webapp?
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// launch browser on localhost
}
Below code worked for me:
#EventListener({ApplicationReadyEvent.class})
void applicationReadyEvent() {
System.out.println("Application started ... launching browser now");
browse("www.google.com");
}
public static void browse(String url) {
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("rundll32 url.dll,FileProtocolHandler " + url);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#SpringBootApplication
#ComponentScan(basePackageClasses = com.io.controller.HelloController.class)
public class HectorApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(HectorApplication.class, args);
openHomePage();
}
private static void openHomePage() throws IOException {
Runtime rt = Runtime.getRuntime();
rt.exec("rundll32 url.dll,FileProtocolHandler " + "http://localhost:8080");
}
}
You could do it by some java code. I am not sure if spring boot has something out of the box.
import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class Browser {
public static void main(String[] args) {
String url = "http://www.google.com";
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("xdg-open " + url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
I've recently been attempting to get this working myself, I know it's been a while since this question was asked but my working (and very basic/simple) solution is shown below. This is a starting point for anyone wanting to get this working, refactor as required in your app!
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
openHomePage();
}
private static void openHomePage() {
try {
URI homepage = new URI("http://localhost:8080/");
Desktop.getDesktop().browse(homepage);
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
}
}
If you package the application as a WAR file, configure an application server, like Tomcat, and restart the configured application server through your IDE, IDEs can automatically open a browser-tab.
If you want to package your application as a JAR file, your IDE will not be able to open a web browser, so you have to open a web browser and type the desired link(localhost:8080). But in the developing phase, taking these boring steps might be very tedious.
It is possible to open a browser with Java programming language after the spring-boot application gets ready. You can use the third-party library like Selenium or use the following code snippet.
The code snippet to open a browser
#EventListener({ApplicationReadyEvent.class})
private void applicationReadyEvent()
{
if (Desktop.isDesktopSupported())
{
Desktop desktop = Desktop.getDesktop();
try
{
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e)
{
e.printStackTrace();
}
} else
{
Runtime runtime = Runtime.getRuntime();
String[] command;
String operatingSystemName = System.getProperty("os.name").toLowerCase();
if (operatingSystemName.indexOf("nix") >= 0 || operatingSystemName.indexOf("nux") >= 0)
{
String[] browsers = {"opera", "google-chrome", "epiphany", "firefox", "mozilla", "konqueror", "netscape", "links", "lynx"};
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < browsers.length; i++)
{
if (i == 0) stringBuffer.append(String.format("%s \"%s\"", browsers[i], url));
else stringBuffer.append(String.format(" || %s \"%s\"", browsers[i], url));
}
command = new String[]{"sh", "-c", stringBuffer.toString()};
} else if (operatingSystemName.indexOf("win") >= 0)
{
command = new String[]{"rundll32 url.dll,FileProtocolHandler " + url};
} else if (operatingSystemName.indexOf("mac") >= 0)
{
command = new String[]{"open " + url};
} else
{
System.out.println("an unknown operating system!!");
return;
}
try
{
if (command.length > 1) runtime.exec(command); // linux
else runtime.exec(command[0]); // windows or mac
} catch (IOException e)
{
e.printStackTrace();
}
}
}
Using Selenium to open a browser
To use the selenium library add the following dependency to your pom.xml file.
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
Then in your main class, add the following code snippet.
#EventListener({ApplicationReadyEvent.class})
private void applicationReadyEvent()
{
String url = "http://localhost:8080";
// pointing to the download driver
System.setProperty("webdriver.chrome.driver", "Downloaded-PATH/chromedriver");
ChromeDriver chromeDriver = new ChromeDriver();
chromeDriver.get(url);
}
Notice: It is possible to use most of the popular browsers like FirefoxDriver, OperaDriver, EdgeDriver, but it is necessary to download browsers' drivers beforehand.
Runtime rt = Runtime.getRuntime();
try {
rt.exec("cmd /c start chrome.exe https://localhost:8080");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The code above worked for me. Change chrome.exe to the browser of your choice and Url to to your choice.
Note: You must include the scheme - http or https, and the browser you choose must me installed, else your app will run without opening the browser automatically.
Works only for windows though.
I am writing an application that needs to load a jar periodically. The Jar fetches the content of a website making use of HTMLUnit.When this jar is run from commond prompt it runs as expected. But when I run it using java code by making use of Runtime, it blocks at the place , page= webClient.getPage(locationToPing);
and doesnt proceed furhter.
The Jar contains only one java class as given below,
package tempproj2;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Fetcher {
String locationToPing;
volatile WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
HtmlPage page ;
public static final long SLEEP_TIME_IF_CONNECTION_WAS_REFUSED=10000; //SECS
public long connectionRefusedTime=0;
private static Fetcher theOnlyInstanceOfThisClass=new Fetcher();
public static Fetcher getInstance(){
return theOnlyInstanceOfThisClass;
}
private Fetcher(){
init();
fetchUsingGet();
}
private void init(){
locationToPing="http://www.mail.yahoo.com";
}
private void fetchUsingGet(){
try {
System.out.println("-----------Start 1 --------------") ;
webClient.setUseInsecureSSL(true);
webClient.setThrowExceptionOnScriptError(false);
System.out.println("-----------Start 2 --------------") ;
webClient.setJavaScriptEnabled(true);
System.out.println("-----------Start 3 --------------") ;
webClient.setTimeout(5000); //30 secs - its int n not long be careful abt it.
System.out.println("-----------Start 4 --------------locationToPing="+locationToPing) ;
page= webClient.getPage(locationToPing);
System.out.println("-----------Start 5 --------------"+page.asXml()) ;
} catch (Exception ex) {
System.out.println("-----------IC Fetecher Error here --------------"+ex.getMessage()) ;
connectionRefusedTime=System.currentTimeMillis();
ex.printStackTrace();
}
}
private void reload(){
if(page==null){
fetchUsingGet();
return;
}
try {
page=(HtmlPage)page.refresh();
} catch (java.net.SocketTimeoutException ex) {
fetchUsingGet();
ex.printStackTrace();
}catch(IOException ex){
ex.printStackTrace();
}
}
public static void main(String ar[]){
Fetcher fetcher=new Fetcher();
while(true){
try {
Thread.sleep(4*1000);
} catch (InterruptedException ex) {
Logger.getLogger(Fetcher.class.getName()).log(Level.SEVERE, null, ex);
}
fetcher.reload();
}
}
}
Given below are the different ways I tried to run the above code
Run the class as it is - Runs fine.
Make a Jar of the above class and run from the command prompt using java -jar , command - Runs fine.
Make a Jar of above class and run it from another java class using the following code,
try {
String execCmd="java -jar "+downloadApplicationJarLocation.getAbsolutePath();
Process pr=Runtime.getRuntime().exec(execCmd) ;
InputStreamReader is = new InputStreamReader(pr.getInputStream());
BufferedReader br = new BufferedReader(is);
String line = null;
String processMessage="";
while ((line = br.readLine()) != null) {
System.err.println("Line 1 "+line) ;
processMessage+=line;
}
System.out.println("Finished ");
is.close();
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
But when I try the above code only the code up to page= webClient.getPage(locationToPing); is executed and gets blocked. "Start 5" is never printed on the screen.
I modifed the above code and instead of directly calling the e Java -jar command in the Runtime.exec(), I placed it in a batch file and called this batch file.
Process pr=Runtime.getRuntime().exec(batchFileLocation) ;
Now it executed as expected and didnt block the code.Also "Start 5" gets printed on the screen.
My application needs to invoke the jar periodically from java and destroy the previous process if any. So Option 4 doesnt hold good for me as the subprocess is stil alive and not very easy to destroy the subprocess.
Option 3 is the ideal way for me but am quite not able to understand why does it get blocked and doesnt proceed any longer? Is it something to do with threading? Am I using HTMLUnit the way how it is supposed to be used?
Thanks in Advance