Git Product home page Git Product logo

ea-async's Introduction

EA Async

Release Maven Central Javadocs Build Status

EA Async implements Async-Await methods in the JVM. It allows programmers to write asynchronous code in a sequential fashion.

It is heavily inspired by Async-Await on the .NET CLR, see Asynchronous Programming with Async and Await for more information.

Who should use it?

EA Async should be used to write non-blocking asynchronous code that makes heavy use of CompletableFutures or CompletionStage. It improves scalability by freeing worker threads while your code awaits other processes; And improves productivity by making asynchronous code simpler and more readable.

Developer & License

This project was developed by Electronic Arts and is licensed under the BSD 3-Clause License.

Examples

With EA Async

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        await(inventory.giveItem(itemTypeId));
        return completedFuture(true);
    }
}

In this example Bank.decrement returns CompletableFuture<Boolean> and Inventory.giveItem returns CompletableFuture<String>

EA Async rewrites the calls to Async.await making your methods non-blocking.

The methods look blocking but are actually transformed into asynchronous methods that use CompletableFutures to continue the execution as intermediary results arrive.

Without EA Async

This is how the first example looks without EA Async. It is a bit less readable.

import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        return bank.decrement(cost)
            .thenCompose(result -> {
                if(!result) {
                    return completedFuture(false);
                }
                return inventory.giveItem(itemTypeId).thenApply(res -> true);
            });
    }
}

This is a small example... A method with a few more CompletableFutures can look very convoluted.

EA Async abstracts away the complexity of the CompletableFutures.

With EA Async (2)

So you like CompletableFutures? Try converting this method to use only CompletableFutures without ever blocking (so no joining):

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class Store
{
    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost)
    {
        if(!await(bank.decrement(cost))) {
            return completedFuture(false);
        }
        try {
            await(inventory.giveItem(itemTypeId));
            return completedFuture(true);
        } catch (Exception ex) {
            await(bank.refund(cost));
            throw new AppException(ex);
        }
    }
}

Got it? Send it to us. It probably looks ugly...

Getting started

EA Async currently supports JDK 8-10.

It works with Java and Scala and should work with most JVM languages. The only requirement to use EA Async is that must be used only inside methods that return CompletableFuture, CompletionStage, or subclasses of CompletableFuture.

Using with maven

<dependency>
    <groupId>com.ea.async</groupId>
    <artifactId>ea-async</artifactId>
    <version>1.2.3</version>
</dependency>

Gradle

'com.ea.async:ea-async:1.2.3'

Instrumenting your code

Option 1 - JVM parameter

Start your application with an extra JVM parameter: -javaagent:ea-async-1.2.3.jar

 java -javaagent:ea-async-1.2.3.jar -cp your_claspath YourMainClass args...

It's recommended to add this as a default option to launchers in IntelliJ projects that use ea-async.

Option 2 - Runtime

On your main class or as early as possible, call at least once:

Async.init();

Provided that your JVM has the capability enabled, this will start a runtime instrumentation agent. If you forget to invoke this function, the first call to await will initialize the system (and print a warning).

This is a solution for testing and development, it has the least amount of configuration. It might interfere with JVM debugging. This alternative is present as a fallback.

Option 3 - Run instrumentation tool

The ea-async-1.2.3.jar is a runnable jar that can pre-instrument your files.

Usage:

java -cp YOUR_PROJECT_CLASSPATH -jar ea-async-1.2.3.jar classDirectory

Example:

java -cp guava.jar;commons-lang.jar  -jar ea-async-1.2.3.jar target/classes

After that all the files in target/classes will have been instrumented. There will be no references to Async.await and Async.init left in those classes.

Option 4 - Build time instrumentation, with Maven - Preferred

Use the ea-async-maven-plugin. It will instrument your classes in compile time and remove all references to Async.await and Async.init().

With build time instrumentation your project users won't need to have EA Async in their classpath unless they also choose to use it. This means that EA Async does not need to be a transitive dependency.

This is the best option for libraries and maven projects.

<build>
    <plugins>
        <plugin>
            <groupId>com.ea.async</groupId>
            <artifactId>ea-async-maven-plugin</artifactId>
            <version>1.2.3</version>
            <executions>
                <execution>
                    <goals>
                        <goal>instrument</goal>
                        <goal>instrument-test</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

ea-async's People

Contributors

coder17934 avatar danielsperry avatar elventear avatar fleex255 avatar joehegarty avatar johnou avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ea-async's Issues

How to use ea-sync in spring boot

Hi, thanks for great jobs!

I tried this in spring boot service, I found that await works like sync function to service, am I right ?

consider codes:

`

@ResponseBody()
@PostMapping("query.do")
public QueryResult query(@RequestParam int pageNum) {
    QueryResult result = new QueryResult(); <1>
    result.setResult(await(queryResult(pageNum))); <2>
    return result; <3>
}

`

In fact, this function only return after <2> queryResult is done?

Class Instrumentation breaks when local variable set to null

If you initialize a local variable to null, then call an await() within a try catch block, you get ClassNotFoundException on the class in which you did that, during that classes initialization.

Simply by removing the null initialization works around the issue.

  @Async
  public Task<Void> doStuff(Task<Void> otherStuff) {

    String x = null;        //bad
    //String x;             //ok

    try {
      await(otherStuff);
    } catch (Exception e) {
      throw e;
    }
    return Task.done();

  }

Use with GWT

Hi, is there any way to use this for GWT? I tried to put <inherits name="com.ea.async.Async" /> in my GdxDefinition.gwt.xml and api "com.ea.async:ea-async:$eaAsyncVersion:sources" in my GWT build.gradle but the build fails. I already used await all over the place in my desktop and Android code so it would be too troublesome to redo all of that and remove this library.

debugging transformed code

Hi, first I just want to say - great job!

I noticed that when I use this library I cannot debug a method that has been modified, when I try to I receive the following error:
JDWP exit error JVMTI_ERROR_NONE(0): getting frame location [stepControl.c:641]

is this a limitation that you planning to resolve?

How to cancel a Promise ?

How do you cancel a Promise that was submitted to await() ?
Will I be able to call .cancel() while it's being processed ?

I suggest adding an async static method to the Async class

I suggest adding an async static method to the Async class,like this

public static <T>CompletableFuture<T> async(Supplier<T> supplier){
      return CompletableFuture.supplyAsync(supplier);
}

public static <T> CompletableFuture<T> async(T object){
      return CompletableFuture.completedFuture(object);
}

The reason is that providing a more convenient way to create asynchronous tasks is the default choice

The program will be written like this

public class TestMain {

    public static void main(String[] args) throws InterruptedException {
        Async.init();
        TestMain main = new TestMain();
        CompletableFuture<Boolean> call = main.call();
//        Boolean aBoolean = call.get();
//        System.out.println(aBoolean);
        call.thenAccept((result) -> {
            System.out.println(result);
        });
        Thread.sleep(10000);
    }

    public CompletableFuture<Boolean> call(){
        Boolean await = await(isExist());
        Boolean await1 = await(timeout());
        return async(await);

    }


    public CompletableFuture<Boolean> isExist(){
        return async(() -> true);
    }

    public CompletableFuture<Boolean> timeout(){
        return async(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return false;
        });
    }
}

This will hide the details of constructing CompletableFuture
What do you think?

Await in loops cause memory leak

Hi,

I am reporting this observation that came up when we noticed our instances getting OOM killed.

This happens in any sort of loop, if the future completes instantly, no issue, but if it enters the synthetic method that the instrumentation creates, all the completable futures will not be GC'd till that method exits.

If you have this loop logic in one method and another method awaits on it, the problem persists, but now in the "awaiting" method.

If you lets say change infinite loops to limited for's, now the same "build-up" of futures will happen on the method that awaits on the looping method to complete (if that awaiting method is looping/retrying itself).

Recursive calls, separate thread completion and so on all retain the same issue.

Is there a way to attempt fixing this, I am willing to contribute but I lack experience on this specific instrumentation topic.

Thank you.

Wrap return types of methods that use await into CompletableFuture automatically

Hi! Thanks for the great library.

There's a thing in this library that annoys me when I use it, and hope that you can add.
In C#, just like in this library everything after the await keyword is converted into a callback under the hood.
In addition, async methods that use the keyword await must return Task (or void, but not recommended), just like in this library where every method that uses the await method needs to return a CompletableFuture.
Since when you use the await method you get the desired type on the awaited method, straight ahead, no need to deal with CompletableFutures, but the problem is that you have to return one.
I personally just wrap it with CompletableFuture.completedFuture(awaitedValue), but that can be annoying when you have a lot of async methods.

Here's an example:

public CompletableFuture<AudioTrack> search(String query) {
    var track = await(youTubeProvider.searchAsync(query));
    track.supplier = "Example usage";
    track.setDate(LocalTime.now());
    return CompletableFuture.completedFuture(track);
}

Imagine having huge amount of methods just like that.
This causes huge frustration and makes the code much longer, since I have to upcast the wrapped value inside the CompletableFuture.

I would be very happy to see the instrumental tool converting a return of any awaited TValue into a CompletableFuture<TValue>.
So my code will look like this:

public CompletableFuture<AudioTrack> search(String query) {
    var track = await(youTubeProvider.searchAsync(query));
    track.supplier = "Example usage";
    track.setDate(LocalTime.now());
    return track;
}

The track is automatically wrapped into a CompletableFuture<AudioTrack>.

I hope I managed to express myself and you got my point.
Thank you very much! You're saving my life from callback hell!

P.S. Perhaps I'm using it not correctly, I'll be very happy to learn the appropriate way.

Sounds like a good idea...

...does not work.

Crashes immediately in Async.init()

2023-06-06 16:57:53.160  3727-3727  AndroidRuntime          com.example.myapp                E  FATAL EXCEPTION: main
                                                                                                    Process: com.example.myapp, PID: 3727
                                                                                                    java.lang.ExceptionInInitializerError

the maven plugin running an error

I use intellij idea
command is mvn clean install
the error is

[INFO] --- maven-install-plugin:2.4:install (default-install) @ async ---
[WARNING] Error injecting: org.apache.maven.artifact.installer.DefaultArtifactInstaller
com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Error injecting: private org.eclipse.aether.spi.log.Logger org.apache.maven.repository.internal.DefaultVersionRangeResolver.logger
  while locating org.apache.maven.repository.internal.DefaultVersionRangeResolver
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.VersionRangeResolver
    for parameter 2 at org.eclipse.aether.internal.impl.DefaultDependencyCollector.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultDependencyCollector
  while locating java.lang.Object annotated with *
  at org.eclipse.sisu.wire.LocatorWiring
  while locating org.eclipse.aether.impl.DependencyCollector
    for parameter 5 at org.eclipse.aether.internal.impl.DefaultRepositorySystem.<init>(Unknown Source)
  while locating org.eclipse.aether.internal.impl.DefaultRepositorySystem
  while locating java.lang.Object annotated with *
  while locating org.apache.maven.artifact.installer.DefaultArtifactInstaller
Caused by: java.lang.IllegalArgumentException: Can not set org.eclipse.aether.spi.log.Logger field org.apache.maven.repository.internal.DefaultVersionRangeResolver.logger to org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
	at java.lang.reflect.Field.set(Field.java:764)
	at org.eclipse.sisu.bean.BeanPropertyField.set(BeanPropertyField.java:72)
	at org.eclipse.sisu.plexus.ProvidedPropertyBinding.injectProperty(ProvidedPropertyBinding.java:48)
	at org.eclipse.sisu.bean.BeanInjector.injectMembers(BeanInjector.java:52)
	at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:140)
	at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:114)
	at com.google.inject.internal.ConstructorInjector.access$000(ConstructorInjector.java:32)
	at com.google.inject.internal.ConstructorInjector$1.call(ConstructorInjector.java:89)
	at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:115)
	at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:133)
	at com.google.inject.internal.ProvisionListenerStackCallback.provision(ProvisionListenerStackCallback.java:68)
	at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:87)
	at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:267)
	at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:56)
	at com.google.inject.internal.InjectorImpl$2$1.call(InjectorImpl.java:1016)
	at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103)
	at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1012)
	at org.eclipse.sisu.inject.Guice4$1.get(Guice4.java:162)
	at org.eclipse.sisu.inject.LazyBeanEntry.getValue(LazyBeanEntry.java:81)
	at org.eclipse.sisu.wire.BeanProviders.firstOf(BeanProviders.java:179)
	at org.eclipse.sisu.wire.BeanProviders$7.get(BeanProviders.java:160)
	at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
	at com.google.inject.internal.InternalFactoryToInitializableAdapter.provision(InternalFactoryToInitializableAdapter.java:53)
	at com.google.inject.internal.ProviderInternalFactory$1.call(ProviderInternalFactory.java:65)
	at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:115)
	at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:133)
	at com.google.inject.internal.ProvisionListenerStackCallback.provision(ProvisionListenerStackCallback.java:68)
	at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:63)
	at com.google.inject.internal.InternalFactoryToInitializableAdapter.get(InternalFactoryToInitializableAdapter.java:45)
	at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
	at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
	at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:104)
	at com.google.inject.internal.ConstructorInjector.access$000(ConstructorInjector.java:32)
	at com.google.inject.internal.ConstructorInjector$1.call(ConstructorInjector.java:89)
	at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:115)
	at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:133)
	at com.google.inject.internal.ProvisionListenerStackCallback.provision(ProvisionListenerStackCallback.java:68)
	at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:87)
	at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:267)
	at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:56)
	at com.google.inject.internal.InjectorImpl$2$1.call(InjectorImpl.java:1016)
	at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
	at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1012)
	at org.eclipse.sisu.inject.Guice4$1.get(Guice4.java:162)
	at org.eclipse.sisu.inject.LazyBeanEntry.getValue(LazyBeanEntry.java:81)
	at org.eclipse.sisu.wire.BeanProviders.firstOf(BeanProviders.java:179)
	at org.eclipse.sisu.wire.BeanProviders$7.get(BeanProviders.java:160)

Too much, I only posted part of it
my pom file is

<?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.dun</groupId>
    <artifactId>async</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.ea.async</groupId>
            <artifactId>ea-async</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.ea.async</groupId>
                <artifactId>ea-async-maven-plugin</artifactId>
                <version>1.1.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>instrument</goal>
                            <goal>instrument-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
</project>

I guess it's not related to development tools? You used eclipse when developing this plugin, so it led to some coupling you didn't expect?

What is the value of this?

await(blockSomeThingFuture());

just only equals to

this.blockSomeThingFuture().toCompletableFuture().join(); // block!!!

Why is it so complicated?

Or I didn’t understand, I look forward to your sharing

Error instrumenting infinite loop

package test;

import java.util.concurrent.CompletableFuture;
import com.ea.async.Async;

public class TestAsync {
	public static CompletableFuture<Void> test() {
		for(;;) Async.await(new CompletableFuture<Void>());
	}
	public static void main(String[] args) {
		Async.init();
	}
}

java -cp ../lib/asm-debug-all-5.0.4.jar;. -javaagent:../lib/async-stub.jar test.TestAsync

java.lang.RuntimeException: Error instrumenting: test/TestAsync
at com.ea.async.instrumentation.Transformer.transform(Transformer.java:163)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
......
Caused by: java.lang.IllegalStateException
at org.objectweb.asm.MethodWriter.visitFrame(MethodWriter.java:659)
at org.objectweb.asm.tree.FrameNode.accept(FrameNode.java:148)
at org.objectweb.asm.tree.InsnList.accept(InsnList.java:162)
at org.objectweb.asm.tree.MethodNode.accept(MethodNode.java:817)
at org.objectweb.asm.tree.MethodNode.accept(MethodNode.java:727)
at org.objectweb.asm.tree.ClassNode.accept(ClassNode.java:412)
at com.ea.async.instrumentation.Transformer.transform(Transformer.java:337)
at com.ea.async.instrumentation.Transformer.transform(Transformer.java:153)
... 15 more

VerifyError with CompletionStage parameters

First I'd like to congratulate you on going 1.0. I've been watching this project since it was a part of Orbit last year with anticipation as I currently write a lot of asynchronous code in Java and having come from C# found it incredibly tedious, even after the addition of CompletableFuture<T>.

I am currently trying to play with a sample project to get my feet wet and I'm getting a VerifyError when I try to run the project. I have the two following source files:

Main.java
package com.halofour;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

public class Main {
    public static void main(String[] args) throws Throwable {
        CompletableFuture<String> future = new CompletableFuture<>();
        CompletionStage<String> stage = MyAsyncClass.testAsync(future);
    }
}
MyAsyncClass.java
package com.halofour;

import java.util.concurrent.CompletionStage;

import static com.ea.async.Async.await;
import static java.util.concurrent.CompletableFuture.completedFuture;

public class MyAsyncClass {
    public static CompletionStage<String> testAsync(CompletionStage<String> stage) {
        String result = await(stage);
        return completedFuture(result);
    }
}

And my pom file is as follows:

<?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">
    <name>sandbox</name>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.halofour</groupId>
    <artifactId>sandbox</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>buildnumber-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
                <configuration>
                    <forkCount>1</forkCount>
                    <systemPropertyVariables>
                        <unit-test>true</unit-test>
                    </systemPropertyVariables>
                </configuration>
            </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>
                    <maxmem>512m</maxmem>
                    <meminitial>128m</meminitial>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.5</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.halofour.Main</mainClass>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                        <manifestEntries>
                            <Implementation-Build>${project.version}</Implementation-Build>
                            <Build-Version>${project.version}</Build-Version>
                            <Build-Time>${maven.build.timestamp}</Build-Time>
                        </manifestEntries>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <finalName>sandbox</finalName>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.ea.async</groupId>
                <artifactId>ea-async-maven-plugin</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>instrument</goal>
                            <goal>instrument-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.ea.async</groupId>
            <artifactId>ea-async</artifactId>
            <version>1.0.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

As you can see there is not a lot going on here. However, when I build the project and run it I get the following error:

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    com/halofour/MyAsyncClass.async$testAsync(Ljava/util/concurrent/CompletionStage;Ljava/util/concurrent/CompletionStage;ILjava/lang/Object;)Ljava/util/concurrent/CompletableFuture; @42: invokevirtual
  Reason:
    Type 'java/util/concurrent/CompletionStage' (current frame, stack[0]) is not assignable to 'java/util/concurrent/CompletableFuture'
  Current Frame:
    bci: @42
    flags: { }
    locals: { 'java/util/concurrent/CompletionStage', 'java/util/concurrent/CompletionStage', 'java/util/concurrent/CompletionStage', 'java/lang/Object' }
    stack: { 'java/util/concurrent/CompletionStage', 'java/util/function/Function' }
  Bytecode:
    0x0000000: 1caa 0000 0000 004f 0000 0000 0000 0001
    0x0000010: 0000 0017 0000 004b 2a59 b900 1301 00b6
    0x0000020: 0019 9a00 194d 2cb8 001f b600 232a 2c11
    0x0000030: 0001 ba00 3700 00b6 003a b0b9 0013 0100
    0x0000040: b600 3ec0 0040 4c2b b800 43b0 2ba7 ffee
    0x0000050: bb00 4a59 b700 4bbf                    
  Stackmap Table:
    full_frame(@24,{Object[#15],Object[#15],Integer,Object[#4]},{})
    full_frame(@59,{Object[#15]},{Object[#15]})
    full_frame(@76,{Object[#15],Object[#15],Integer,Object[#4]},{})
    full_frame(@80,{Object[#15],Object[#15],Integer,Object[#4]},{})

    at com.halofour.Main.main(Main.java:13)

If I change the parameter type of the first parameter in the MyAsyncClass#testAsync method from CompletionStage<T> to CompletableFuture<T> it does seem to work correctly.

ea-async copying annotations to instrument-generated methods

I'm testing ea-async with a Spring 5 application I am working on. This is a part of a tech spike/evaluation for implementing asynchronous programming throughout our team. What I've noticed is that the ea-async instrumentation is copying the annotations of the instrumented method to the generated methods and in some cases this is causing problems with Spring.

For example, take the following controller:

@RestController
public class HelloWorldController {

    @Inject
    private AsyncService service;

    @RequestMapping("/hello")
    public CompletionStage<String> get() {
        CompletionStage<String> stage1 = service.getGreetingAsync();
        CompletionStage<String> stage2 = service.getGreetingAsync();
        String result1 = await(stage1);
        String result2 = await(stage2);

        return CompletableFuture.completedFuture(result1 + result2);
    }
}

The instrumentation rewrites this into:

@RestController
public class HelloWorldController {
    @Inject
    private AsyncService service;

    public HelloWorldController() {
    }

    @RequestMapping({"/hello"})
    public CompletionStage<String> get() { /* elided */ }

    @RequestMapping({"/hello"})
    private static CompletableFuture async$get(HelloWorldController var0, CompletionStage stage1, CompletionStage stage2, CompletionStage var3, String result2, int var5, Object var6) { /* elided */ }
}

This causes Spring to fail mapping the controller with the following message:

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'helloWorldController' method 
private static java.util.concurrent.CompletableFuture com.comcast.controller.HelloWorldController.async$get(com.comcast.controller.HelloWorldController,java.util.concurrent.CompletionStage,java.util.concurrent.CompletionStage,java.util.concurrent.CompletionStage,java.lang.String,int,java.lang.Object)
to {[/hello]}: There is already 'helloWorldController' bean method

This can be worked around by having only using Async.await in non-annotated methods, however my concern is that this will make other folks on my team more apprehensive about adopting ea-async.

the meaning of "executePhase" and "executeGoal" in plugin.xml ?

with this paramter in plugin.xml , plugin will fork some plugin executions ,and run twice ,such as
maven-resources-plugin
maven-compiler-plugin

can you explain the meaning of "executePhase" and "executeGoal" and why should we run the plugin before "process-classes" phase again?

Without EA Async (2)

  public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost) {
    return bank.decrement(cost)
        .thenCompose(decResult -> {
          if (decResult) return completedFuture(false);
          return completedFuture(null) // defer error
              .thenCompose(_void -> inventory.giveItem(itemTypeId))
              .handle((giveResult, t) -> {
                if (t == null) return completedFuture(true);
                return bank.refund(cost)
                    .<Boolean>thenApply(refundResult -> {
                      throw new RuntimeException(t);
                    });
              })
              .thenCompose(Function.identity());
        });
  }

I'm not saying it's prettier than the example, but I don't think this is ugly.

Unwrap CompletionException automatically

Hi! Thanks for the nice library. But I have a small issue using it. If you want to catch an exception from await call it always has been wrapped into CompletionException, and you should write extra checks just to verify nested exception.

Example:

CompletableFuture<String> foo() {
    return failedFuture(new MyException());
}

CompletableFuture<String> bar() {
    try {   
        return await(foo());
    } catch (MyException e) {
        // never called
    } catch (CompletionException e) {
        if (e.getCause() instanceof MyException) {
            var ex = (MyException) e.getCause();
            // so now you can access MyException instance
        } else {
            throw e;
        }
    }
}

It would be great to have an easy way to avoid unnecessary wrapping.

Problems with ea-async-maven-plugin

Hi,
i just found your amazing async await library and wanted to use maven for the integration, but unfortunately i got an error after entering the ea-async-maven-plugin into my pom.xml.
I git the following errors:

Plugin execution not covered by lifecycle configuration: com.ea.async:ea-async-maven-plugin:1.2.3:instrument (execution: default, phase: process-classes)
Plugin execution not covered by lifecycle configuration: com.ea.async:ea-async-maven-plugin:1.2.3:instrument-test (execution: default, phase: process-test-classes)

I used the provided example:

<plugin>
    <groupId>com.ea.async</groupId>
    <artifactId>ea-async-maven-plugin</artifactId>
    <version>1.2.3</version>
       <executions>
          <execution>
             <goals>
                <goal>instrument</goal>
                <goal>instrument-test</goal>
             </goals>
          </execution>
      </executions>
  </plugin>

Any ideas what i am doing wrong?
Thanks in advance.

provide annotation processor

I'm just trying out ea-async on a project... while compiling with maven works great, I'm having trouble integrating this in my dev-workflow where I'm using intellij idea.

Usually, libraries like this one (e.g. immutables.org) provide a annotation-processor that I can plug into my IDE workflow.. at the moment, I'm unable to get idea to run the maven plugin on automatic recompilation (which I have enabled through JRebel)

Custom Executor Injection

I think you really did a fantastic job.

According to you, Is it possibile to inject, somehow, a custom Executor to let the generated CompletableFutures asynchronously run into a specific Context (in my case, Vert.x)?

If a lib verticalization is needed, what point of the source do you suggest to edit?

Java 14 Support?

Nice library guys - have been using it for a while - makes non blocking Rest API code much easier to write reliably.

Just wondered if it could be updated to support the latest Java, which I was trying to use?
I believe the below issue is related to the version of ASM dependencies.

Not massively urgent, but nice to keep your library working with latest versions.

Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 58
at com.ea.async.shaded.org.objectweb.asm.ClassReader.(ClassReader.java:195)
at com.ea.async.shaded.org.objectweb.asm.ClassReader.(ClassReader.java:176)
at com.ea.async.shaded.org.objectweb.asm.ClassReader.(ClassReader.java:162)
at com.ea.async.instrumentation.Transformer.transform(Transformer.java:150)

Method references `Async::await` are not taken away

The instrumentation tool takes away all Async.await occurrences, but does not take away Async::await. I think this is a bug?

E.g.

final List<CompletableFuture<Void>> futures = new ArrayList<>();
futures.add(CompletableFuture.completedFuture(null));
futures.stream().map(Async::await).collect(Collectors.toList());

The Async::await stays after instrumentation.

Derived project licence question

I have used this code as a basis for an async/await transformer. I have changed the api significantly, which is why I am not going to submit a pull request. I would not mind discussing the changes though, so we can make both projects better or possibly merge them at some point, but this is for another time.

I have retained the licence text in 2 source filed that I used from this project.
Q1: Is it enough to retain the licence text for these files only or does the licence automatically apply to all the artifact?

I would like to publish the compiled artifact to maven central. Since the licence states:

Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

Q2: Do I need to add anything to the compiled artifact? or just deploying the source jar with the licence text in the source files be enough?

Thanks in advance

Support arbitrary implementations of CompletionStage<T>

Currently there is support for instrumenting methods that return/await classes that derive from CompletableFuture<T>. How about also supporting classes or interfaces that implement or extend CompletionStage<T>, with which the class would be treated as a CompletionStage<T> during instrumentation?

I've seen a couple of libraries where methods returns interfaces that extend CompletionStage<T>. For example, the Lettuce Redis client offers an asynchronous API that returns a RedisFuture<T> interface which extends CompletionStage<T> and Future<T> interfaces as well as providing a few additional methods. The internal implementation of that interface is derived from CompletableFuture<T>. Because of this the library isn't supported by ea-async.

Example 2 with just CompletableFuture

Something like this? You can argue whether it looks ugly but I still think it's not that bad.

    public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost) {
        CompletableFuture<Boolean> cf = new CompletableFuture<Boolean>();

        bank.decrement(cost).thenAccept(ok -> {
            if (!ok) {
                cf.complete(false);
            } else {
                inventory.giveItem(itemTypeId).whenComplete((s, ex) -> {
                    if (ex == null) {
                        cf.complete(true);
                    } else {
                        bank.refund(cost).thenAccept(ok2 -> {
                            cf.completeExceptionally(new AppException(ex));
                        });
                    }
                });
            }
        });

        return cf;
    }

ea-async with Java 9

I'm testing using ea-async with a SpringBoot 5.x application I am working on. When I try to compile and run this on Java 9 I get the following error:

java.lang.IncompatibleClassChangeError: Method java.util.function.Function.identity()Ljava/util/function/Function; must be InterfaceMethodref constant

I am doing the instrumentation at compile-time via the maven plugin.

A quick Googlin' seems to indicate that the Java bytecode validator got a little better/stricter with Java 9 so what worked with Java 8 is no longer valid.

Error with Arrays

The instrumented code:

public final CompletableFuture<Boolean> call(String longString) {
    String[] split = longString.split(" ");
    String name = split[0];
    String surname = split[1];

    //again...
    name = split[0];
    //...
}

Raises me the following exception:

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at it.mvi.core.functionalities.FunctionalitiesHelper.getFunctionality(FunctionalitiesHelper.java:36)
	at it.mvi.core.functionalities.FunctionalitiesManager.executeWork(FunctionalitiesManager.java:128)
	at it.mvi.core.functionalities.FunctionalitiesManager.executeWork(FunctionalitiesManager.java:34)
	at it.mvi.core.functionalities.FunctionalitiesManager.call(FunctionalitiesManager.java:21)
	at com.metaring.homepagecontactformbackend.HomepagecontactformbackendFunctionalitiesManager.contact(HomepagecontactformbackendFunctionalitiesManager.java:16)
	at com.metaring.homepagecontactformbackend.Main.start(Main.java:20)
	at com.metaring.homepagecontactformbackend.Main.main(Main.java:14)
Caused by: java.lang.VerifyError: Inconsistent stackmap frames at branch target 494
Exception Details:
  Location:
    com/metaring/homepagecontactformbackend/ContactFunctionalityImpl.call(Lcom/metaring/homepagecontactformbackend/ContactForm;)Ljava/util/concurrent/CompletableFuture; @494: new
  Reason:
    Type 'java/lang/Object' (current frame, locals[8]) is not assignable to 'java/lang/String' (stack map, locals[8])
  Current Frame:
    bci: @465
    flags: { }
    locals: { 'com/metaring/homepagecontactformbackend/ContactFunctionalityImpl', 'com/metaring/homepagecontactformbackend/ContactForm', 'it/mvi/core/type/factory/DataRepresentationFactory', 'java/lang/String', '[Ljava/lang/String;', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'java/lang/Object', 'java/lang/String', 'java/lang/String', 'it/mvi/core/type/DataRepresentation', 'java/lang/String', 'it/mvi/core/type/DataRepresentation', 'it/mvi/core/type/DataRepresentation' }
    stack: { 'it/mvi/core/type/DataRepresentation' }
  Stackmap Frame:
    bci: @494
    flags: { }
    locals: { 'com/metaring/homepagecontactformbackend/ContactFunctionalityImpl', 'com/metaring/homepagecontactformbackend/ContactForm', 'it/mvi/core/type/factory/DataRepresentationFactory', 'java/lang/String', '[Ljava/lang/String;', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'it/mvi/core/type/DataRepresentation', 'java/lang/String', 'it/mvi/core/type/DataRepresentation', 'it/mvi/core/type/DataRepresentation' }
    stack: { }
  Bytecode:
  ...

It is raised when the class is loaded into ClassLoader for the first time in application.
I am sure that the problem is in that piece of code because I tried a lot of alternatives, and solved using:

List<String> split = Arrays.asList(longString.split(" "));
String name = split.get(0);

//again...
name = split.get(0);

But I want my customers enjoy development experience through my SDK...
Can you help, please?

Java 11

Any plans for LTS Java 11? :)

Says "the method invoking await must return a CompletableFuture" but it does already

If you forget to instrument the code, the wrong warning message is printed:

WARN com.ea.async.Async - Warning: Illegal call to await, the method invoking await must return a CompletableFuture

instead of

Warning: Illegal call to await, static { Async.init(); } must be added to the main program class and the method invoking await must return a CompletableFuture

As shown by the following simple example:

import java.util.concurrent.CompletableFuture;

import com.ea.async.Async;

public class EAsyncTest {

	static CompletableFuture<String> convert(CompletableFuture<?> future) {
		Object result = Async.await(future);
		return CompletableFuture.completedFuture(result.toString());
	}

	public static void main(String[] args) {
		convert(new CompletableFuture<>());
	}
}

This is because calling InitializeAsync.isRunning() triggers the class initialization, and only enters that method once isRunning = true. The only ways to have isRunning() returning false is if either the initialization crashes or if called from multiple threads.

In addition, I think it would be better to throw an exception than calling join(). In the above example this causes a deadlock, and you don't know which method it is referring to.

java.lang.VerifyError is being thrown in specific case

java.lang.VerifyError is being thrown with the following code example:

public class Main2 {
	public static void main(String[] args) throws InterruptedException {
		Async.init();
		
		test()
		.thenRun(() -> System.out.println("DONE"))
		.exceptionally(t -> {t.printStackTrace();return null;});
		
		Thread.sleep(1000);
	}
	
	private static CompletableFuture<TestModel[]> getTestModels() {
		return CompletableFuture.completedFuture(new TestModel[] { new TestModel(1), new TestModel(2) });
	}
	
	private static CompletableFuture<Void> test() {
		TestModel[] testModelArr = await(getTestModels());
		String str = "";

		for (TestModel myModel: testModelArr) {
			str += ":" + await(CompletableFuture.completedFuture(myModel.myInt));
			System.out.println(myModel.myInt.doubleValue());
		}

		System.out.println(str);
		
		return CompletableFuture.completedFuture(null);
	}
	
	private static class TestModel {
		public final Integer myInt;
		
		private TestModel(Integer myInt) {
			this.myInt = myInt;
		}
	}
}

With any of the following changes to the test() method, it no longer throws the error:

  1. removing System.out.println(myModel.myInt.doubleValue());:
private static CompletableFuture<Void> test() {
	TestModel[] testModelArr = await(getTestModels());
	String str = "";

	for (TestModel myModel: testModelArr) {
		str += ":" + await(CompletableFuture.completedFuture(myModel.myInt));
	}

	System.out.println(str);
	
	return CompletableFuture.completedFuture(null);
}
  1. moving up System.out.println(myModel.myInt.doubleValue()); by 1 line:
private static CompletableFuture<Void> test() {
	TestModel[] testModelArr = await(getTestModels());
	String str = "";

	for (TestModel myModel: testModelArr) {
		System.out.println(myModel.myInt.doubleValue());
		str += ":" + await(CompletableFuture.completedFuture(myModel.myInt));
	}

	System.out.println(str);
	
	return CompletableFuture.completedFuture(null);
}
  1. converting testModelArr to list for the for loop:
private static CompletableFuture<Void> test() {
	TestModel[] testModelArr = await(getTestModels());
	String str = "";

	for (TestModel myModel: Arrays.asList(testModelArr)) {
		str += ":" + await(CompletableFuture.completedFuture(myModel.myInt));
		System.out.println(myModel.myInt.doubleValue());
	}

	System.out.println(str);
	
	return CompletableFuture.completedFuture(null);
}

Any idea why this is happening in this specific case?

is this awesome project alive?

I’m introducing this project to my team, it’s really convenience.

Now I notice that last commit is in 2020, why no updates coming.

So is this project alive?

java.lang.VerifyError: on startup

This is a strange one. Under very specific circumstances, our code is getting a verification error on startup when using runtime instrumentation. I've tried stripping it down to its bare essence, but it doesn't really make a lot of sense to me. I'm sure there's a larger pattern I'm not seeing.

Basically you need a local String initialized to null then an numeric variable initialized to anything, and a subsequent await statement.

I get this error, along with a lot of error output: java.lang.VerifyError: Bad local variable type

Here's and example I added to BasicTest.java

    @Test(timeout = 2_000)
    public void testNonInitilized() throws IllegalAccessException, InstantiationException
    {
        final SomethingWithNonInitialized a = new SomethingWithNonInitialized();
        CompletableFuture<String> blocker = new CompletableFuture<>();
        final CompletableFuture<Object> res = a.doSomething(blocker);
        blocker.complete("x");
        assertEquals(":x", res.join());
    }


    public static class SomethingWithNonInitialized
    {
        public CompletableFuture<Object> doSomething(CompletableFuture<String> blocker)
        {
            //these variables must occur in this order.  It doesn't matter if they are set later or not.  
            //Remove the initializers and then it works
            String var2 = null;         //this variable must be a string and initialized to null
            byte var3 = 0;              //this variable must be numeric and initialized to anything
            return CompletableFuture.completedFuture(":" + await(blocker));
        }
    }

Sorry for the ugly formatting. Code formatting isn't working. I've also included BasicTest.java

BasicTest.java.txt

Agent failed to start

At first, when I tried to run my .jar which uses the ea async dependency, I got the error that it couldn't find the class agend in my manifest. Therefore, I added
Agent-Class: com.ea.async.instrumentation.Agent
to my MANIFEST.MF and it seemed to fix this error, but now I got a new one and I really don't know what I am doing wrong.

It's a maven project so that's what I did:

  1. Added the dependency to my pom.xml
  2. Added the plugin to my pom.xml
  3. I rebuild the project, recreated the artifacts to apply possibly missing changes.
  4. I started using it with the import parameter import static com.ea.async.Async.await; like on the examples.

It works fine if I start it in my IDE (Intellij / Javac 11), but does not if I put the compiled .jar (which contains the com.ea.async dir) on my debian 9 server and try to launch it there (it runs with open jdk 11).

I am grateful for any help! πŸ™

This is my error (Servant is the name of my program):

Exception in thread "Attach Listener" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:513)
	at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:535)
Caused by: java.lang.UnsupportedOperationException: adding retransformable transformers is not supported in this environment
	at java.instrument/sun.instrument.InstrumentationImpl.addTransformer(InstrumentationImpl.java:94)
	at com.ea.async.instrumentation.Agent.agentmain(Agent.java:52)
	... 6 more

Agent failed to start!

Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.ea.async.Async.init(Async.java:79)
	at servant.Servant.main(Servant.java:79)

Caused by: java.lang.RuntimeException: Error attaching ea-async java agent
	at com.ea.async.instrumentation.InitializeAsync.<clinit>(InitializeAsync.java:99)
	... 2 more

Caused by: java.lang.RuntimeException: Error activating orbit-async agent from /home/bots/rin/Rin.jar
	at com.ea.async.instrumentation.InitializeAsync.loadAgent(InitializeAsync.java:211)
	at com.ea.async.instrumentation.InitializeAsync.<clinit>(InitializeAsync.java:80)
	... 2 more

Caused by: java.lang.IllegalStateException: Could not self-attach to current VM using external process
	at com.ea.async.shaded.net.bytebuddy.agent.ByteBuddyAgent.installExternal(ByteBuddyAgent.java:486)
	at com.ea.async.shaded.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:420)
	at com.ea.async.shaded.net.bytebuddy.agent.ByteBuddyAgent.attach(ByteBuddyAgent.java:248)
	at com.ea.async.shaded.net.bytebuddy.agent.ByteBuddyAgent.attach(ByteBuddyAgent.java:223)
	at com.ea.async.shaded.net.bytebuddy.agent.ByteBuddyAgent.attach(ByteBuddyAgent.java:210)
	at com.ea.async.instrumentation.InitializeAsync.loadAgent(InitializeAsync.java:205)
	... 3 more

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.