Closed chengenzhao closed 3 years ago
We have discussed this topic Okou said it is probably becoz the Future class of Vert.x doesn't contain then method therefore await doesn't apply to this type And seems like es4x-launcher.jar uses FutureBase of its own rather than FutureBase of Vert.x so is it possible to provide a wrapper of Vert.x api e.g. es4x instead of vertx instance then we could use es4x.deployVerticle(...) return Future type with then method and we could await es4x.deployVerticle(...)
Yes es4x "patches" the FutureBase
class in order to add the extra method:
void then(Value onSuccess, Values onFailure);
However if for some reason the deployVerticle does not call that class (but another implementation) then the await
will not work. I need to reproduce this and see the real class that is coming from the deployVerticle
.
I'm looking at the core code and I'm getting the impression that, as there's is a classloader switch before the deployment that the "patched" FutureBase will not be used, and the "official" one is... If this is the case, then the "patch" is not enough and I need to really hack it to ensure that the right class is loaded.
Wait, I'm running your project and I see that it is a maven project so the "patching" never happens, this means that the thenable support isn't there and the transparent usage of JsonObject/JsonArray
as js json types either...
Yes, it is a maven project because we also have Kotlin code in the project Is there any way to replace ES4X FutureBase instead of Vert.x Core FutureBase in maven project?
I got it to work:
~/Projects/bugs/social-vertex (master)$ java -jar target/social-vertex-0.7.jar
Current Path: /home/paulo/Projects/bugs/social-vertex
Succeeded in deploying verticle
The configuration file: config.json does not exist or in wrong format, use default config.
class: 6fe41a75-0bf1-4cec-b9ff-d8871b947f82
class: c60235fe-bddb-4c4e-b582-21fb0f047c5c
class: a08c9cd7-7bf4-4449-9b5c-e3f41b4a66e4
class: 3ff7a828-6e37-4390-9285-ff25818c6bc1
class: a397eca8-95c1-46c1-ab95-95b5cff2a9c7
class: 2bc3a368-8825-4c0f-95e8-d4f1d9f7930b
cn.net.polyglot.verticle.im.IMTcpServerVerticle is deployed
cn.net.polyglot.verticle.im.IMServletVerticle is deployed
class: 16509885-e85c-481c-9700-e645ed3e874a
cn.net.polyglot.verticle.web.SessionVerticle is deployed
cn.net.polyglot.verticle.WebServerVerticle is deployed
class: 489dbfc5-c563-4382-82a5-8faf1e89d180
cn.net.polyglot.verticle.community.DefaultVerticle is deployed
class: 5ff3dca4-744e-467d-a516-54c7778bd8b6
cn.net.polyglot.verticle.community.LoginVerticle is deployed
class: a83da962-22e3-4354-9a66-a5a51261a659
cn.net.polyglot.verticle.community.CommunityVerticle is deployed
class: 0dde0dcf-f129-468b-92d0-24d3ea50724c
^C~/Projects/bugs/social-vertex (master)$
So the issue is that we miss the "patched" class and this class "must" be loaded first that the remaining jars.
To "hack it" I've run the following code:
package io.reactiverse.es4x;
import io.reactiverse.es4x.asm.FutureBaseVisitor;
import io.reactiverse.es4x.asm.JsonArrayVisitor;
import io.reactiverse.es4x.asm.JsonObjectVisitor;
import io.reactiverse.es4x.commands.Resolver;
import org.eclipse.aether.artifact.Artifact;
import java.io.*;
import java.util.Collections;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class VertxPatch {
public static void main(String[] args) throws IOException {
System.err.println(args[0]);
System.err.println(args[1]);
Resolver resolver = new Resolver();
File coreJar = null;
for (Artifact a : resolver.resolve("io.vertx:vertx-core:" + args[0], Collections.emptyList())) {
if ("io.vertx".equals(a.getGroupId()) && "vertx-core".equals(a.getArtifactId())) {
coreJar = a.getFile();
break;
}
}
if (coreJar == null) {
throw new RuntimeException("Failed to locate the core jar");
}
try (JarInputStream jar = new JarInputStream(new FileInputStream(coreJar))) {
JarEntry je;
byte[] bytes;
File target;
while ((je = jar.getNextJarEntry()) != null) {
switch (je.getName()) {
case "io/vertx/core/json/JsonObject.class":
bytes = new JsonObjectVisitor().rewrite(jar);
target = new File(args[1], "io/vertx/core/json");
target.mkdirs();
try (OutputStream writer = new FileOutputStream(new File(target, "JsonObject.class"))) {
writer.write(bytes);
}
break;
case "io/vertx/core/json/JsonArray.class":
bytes = new JsonArrayVisitor().rewrite(jar);
target = new File(args[1], "io/vertx/core/json");
target.mkdirs();
try (OutputStream writer = new FileOutputStream(new File(target, "JsonArray.class"))) {
writer.write(bytes);
}
break;
case "io/vertx/core/impl/future/FutureBase.class":
bytes = new FutureBaseVisitor().rewrite(jar);
target = new File(args[1], "io/vertx/core/impl/future");
target.mkdirs();
try (OutputStream writer = new FileOutputStream(new File(target, "FutureBase.class"))) {
writer.write(bytes);
}
break;
}
}
}
}
}
This generates the patched 3 classes. The classes are written to target/classes
so they get bundled with your application (this means it will not work with JPMS (but the regular es4x install does the same and doesn't work either) which isn't a real problem I would say.
With this 3 classes then it all works. I could add this class to es4x-pm
jar so it could be used as a "provided" dependency to be run during a "maven build"? Or else we need a maven plugin or something the like:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-asm</id>
<phase>process-test-classes</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>io.reactiverse.es4x.VertxPatch</mainClass>
<arguments>
<argument>${stack.version}</argument>
<argument>${project.build.testOutputDirectory}</argument>
</arguments>
<classpathScope>test</classpathScope>
</configuration>
</plugin>
This seems to get the basic things working:
https://github.com/reactiverse/es4x/pull/461
Add the pm dependency as "provided" as it's not needed at runtime:
<dependency>
<groupId>io.reactiverse</groupId>
<artifactId>es4x-pm</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
Then in the build run the Patch:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-asm</id>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>io.reactiverse.es4x.cli.VertxPatch</mainClass>
<arguments>
<argument>${vertx.version}</argument>
<argument>${project.build.outputDirectory}</argument>
</arguments>
<classpathScope>compile</classpathScope>
</configuration>
</plugin>
@chengenzhao I've prepared a new release 0.14.0
currently if you're testing using maven you can verify the artifacts if you use the following statging maven repo:
https://oss.sonatype.org/content/repositories/ioreactiverse-1147/
@pmlopes it works thx
but weird thing is if we change the code to: for await then the disorder happened again
@chengenzhao what do you mean with "disorder"? Are you saying that the deployment doesn't happen on the loop order?
This behavior is not controlled by vertx or es4x, it's graaljs. The only thing es4x is doing is transforming a Future
to a JS Thenable
. and then graaljs takes over and runs the async operations.
👌,we just wonder for await not works in this way but it is ok, we just use await inside the for loop
Hi Paulo:
We try to migrate our vert.x based project to es4x and we did some progress but seems like there is a problem here if we use await vertx.deployVerticle(...) and it just don't work seems like we need es4x promise or sth. rather than vert.x core future here is the source code of main_verticle.js, we try to deploy verticles and await the return future/promise type https://github.com/fantasy0v0/social-vertex/blob/master/src/main/javascript/cn/net/polyglot/main-verticle.js