Java Deferred/Promise library similar to JQuery.
JDeferred is a Java Deferred/Promise library similar to JQuery's Deferred Object.
Inspired by JQuery and Android Deferred Object.
If you are using JDeferred 1.x, see JDeferred 1.x Documentation
.then(…).filter(…).pipe(…).done(…).fail(…).progress(…).always(…).pipeAlways(…).when(p1, p2, p3, …).then(…).race(p1, p2, p3, …).then(…).settle(p1, p2, p3, …).then(…).when(new Runnable() {…}).race(new Runnable() {…}).settle(new Runnable() {…})Deferred<Integer, Exception, Double> deferred;deferred.resolve(10);deferred.reject(new Exception());deferred.notify(0.80);<dependency>
<groupId>org.jdeferred.v2</groupId>
<artifactId>jdeferred-core</artifactId>
<version>${version}</version>
</dependency>compile 'org.jdeferred.v2:jdeferred-core:${version}'Find available versions on Maven Central Repository.
Compatibility reports between versions:
Deferred deferred = new DeferredObject();
Promise promise = deferred.promise();
promise.done(new DoneCallback() {
public void onDone(Object result) {
...
}
}).fail(new FailCallback() {
public void onFail(Object rejection) {
...
}
}).progress(new ProgressCallback() {
public void onProgress(Object progress) {
...
}
}).always(new AlwaysCallback() {
public void onAlways(State state, Object result, Object rejection) {
...
}
});With the reference to deferred object, you can then trigger actions/updates:
deferred.resolve("done");
deferred.reject("oops");
deferred.notify("100%");Use
.filter(...)instead of.then(...)since 2.0.0-Beta2
Deferred d = …;
Promise p = d.promise();
Promise filtered = p.filter(new DoneFilter<Integer, Integer>() {
public Integer filterDone(Integer result)
return result * 10;
}
});
filtered.done(new DoneCallback<Integer>() {
public void onDone(Integer result) {
// result would be original * 10
System.out.println(result);
}
});
d.resolve(3) -> 30.Use
.pipe(...)instead of.then(...)since 2.0.0-Beta2
Deferred d = ...;
Promise p = d.promise();
p.pipe(new DonePipe<Integer, Integer, Exception, Void>() {
public Deferred<Integer, Exception, Void> pipeDone(Integer result) {
if (result < 100) {
return new DeferredObject<Integer, Void, Void>().resolve(result);
} else {
return new DeferredObject<Integer, Void, Void>().reject(new Exception(...));
}
}
}).done(...).fail(...);
d.resolve(80) -> done!
d.resolve(100) -> fail!
DeferredManager dm = new DefaultDeferredManager();
Promise p1, p2, p3;
// initialize p1, p2, p3
dm.when(p1, p2, p3)
.done(…)
.fail(…)You can also specify a Executor Service for your need.
DeferredManager dm = new DefaultDeferredManager(myExecutorService);You can use Callable and Runnable almost like a Promise without any additional work.
DeferredManager dm = new DefaultDeferredManager();
dm.when(new Callable<Integer>(){
public Integer call() {
// return something
// or throw a new exception
}
}).done(new DoneCallback<Integer>() {
public void onDone(Integer result) {
...
}
}).fail(new FailCallback<Throwable>() {
public void onFail(Throwable e) {
...
}
});If you need to notify progress within your Callable or Runnable, you either need to create your own Deferred object and Promise, or you can use DeferredCallable and DeferredRunnable.
Use your own Deferred object
final Deferred deferred = ...
Promise promise = deferred.promise();
promise.then(…);
Runnable r = new Runnable() {
public void run() {
while (…) {
deferred.notify(myProgress);
}
deferred.resolve("done");
}
}Or, extending DeferredRunnable
DeferredManager dm = …;
dm.when(new DeferredRunnable<Double>(){
public void run() {
while (…) {
notify(myProgress);
}
}
}).then(…);Since 1.0.1
Normally, when using this framework, you would want to do things asynchronously. However, if there is a need to wait for all deferred tasks to finish, you can use Object.wait or Promise.waitSafely methods.
Promise p = dm.when(...)
.done(...)
.fail(...)
synchronized (p)
while (p.isPending()) {
try {
p.wait();
} catch (InterruptedException e) { ... }
}
}Alternatively, you can use a more simplified shortcut
Promise p = dm.when(...)
.done(...)
.fail(...)
try {
p.waitSafely();
} catch (InterruptedException e) {
...
}Now this is pretty cool when used with Java 8 Lambda!
dm.when(() -> {
return "Hey!";
}).done(r -> System.out.println(r));
dm.when(
() -> { return "Hello"; },
() -> { return "World"; }
).done(rs ->
rs.forEach(r -> System.out.println(r.getResult()))
);Calls to when with multiple arguments results in a Promise that signals fail on the first rejection or signals
done with all computed values.
Callable<Integer> c1 = () -> 1;
Callable<Integer> c2 = () -> 2;
Callable<Integer> c3 = () -> 3;
Promise<MultipleResults3<Integer, Integer, Integer>, OneReject<Throwable>, MasterProgress> p = dm.when(c1, c2, c3);
p.done(MultipleResults3<Integer, Integer, Integer> r -> {
Assert.assertEquals(r.getFirst(), 1);
Assert.assertEquals(r.getSecond(), 2);
Assert.assertEquals(r.getThird(), 3);
});Callable<Integer> c1 = () -> 1;
Callable<Integer> c2 = () -> 2;
Callable<Integer> c3 = () -> throw new RuntimeException("boom!");
Promise<MultipleResults3<Integer, Integer, Integer>, OneReject<Throwable>, MasterProgress> p = dm.when(c1, c2, c3);
p.done(MultipleResults3<Integer, Integer, Integer> r -> Assert.fail("should not be called"))
.fail(OneReject<Throwable> r -> Assert.assertEquals(r.getReject().getMessage(), "boom!"));Since 2.0.0
Calls to when with multiple arguments (up to five) will produce results with typesafe getters.
Since 2.0.0
Calls to race with multiple arguments results in a Promise that signals fail on the first rejection or signals
done on the first resolution.
Callable<Integer> c1 = () -> { Thread.sleep(200); return 1; };
Callable<Integer> c2 = () -> { Thread.sleep(100); return 2; };
Callable<Integer> c3 = () -> { Thread.sleep(200); return 3; };
Promise<OneResult<?>, OneReject<Throwable>, Void> p = dm.race(c1, c2, c3);
p.done(OneResult<?> r -> Assert.assertEquals(r.getResult(), 2));Callable<Integer> c1 = () -> { Thread.sleep(200); return 1; };
Callable<Integer> c2 = () -> { Thread.sleep(100); throw new RuntimeException("boom!"); };
Callable<Integer> c3 = () -> { Thread.sleep(200); return 3; };
Promise<OneResult<?>, OneReject<Throwable>, Void> p = dm.race(c1, c2, c3);
p.done(OneResult<?> r -> Assert.fail("should not be called")
.fail(OneReject<Throwable> r -> Assert.assertEquals(r.getReject().getMessage(), "boom!"));Since 2.0.0
Calls to settle with multiple arguments results in a Promise that collects all resolutions and rejections.
Callable<Integer> c1 = () -> { Thread.sleep(200); return 1; };
Callable<Integer> c2 = () -> { Thread.sleep(100); throw new RuntimeException("boom!"); };
Callable<Integer> c3 = () -> { Thread.sleep(200); return 3; };
Promise<AllValues, Throwable, MasterProgress>, Void> p = dm.race(c1, c2, c3);
p.done(AllValues r -> {
Assert.assertEquals(r.get(0).getValue(), 1);
Assert.assertTrue(r.get(1).getValue() instanceof RuntimeException);
Assert.assertEquals(r.get(2).getValue(), 3);
});Since 2.0.0
Sometimes a task may be cancelled while its running and would require ti cleanup any resources it may have allocated. You
may define a task that implements the org.jdeferred2.CancellationHandler interface or pass and extra argument to
DeferredFutureTask with such implementation, for example
final DataSource datasource = ...;
class DatabaseTask extends Runnable, CancellationHandler {
@Override
public void run() {
// perform computation with datasource
}
@Override
public void onCancel() {
try {
datasource.close();
} catch(Exception e) {
throw new IllegalStateException(e);
}
}
}
DeferredFutureTask<X> task = new DeferredFutureTask(new DatabaseTask());
dm.when(task).done(...)You may also pass the CancellationHandler as an additional argument, for example
final DataSource datasource = ...;
class DatabaseTask extends Runnable {
@Override
public void run() {
// perform computation with datasource
}
}
class DatabaseCancellationHandler implements CancellationHandler {
@Override
public void onCancel() {
try {
datasource.close();
} catch(Exception e) {
throw new IllegalStateException(e);
}
}
}
DeferredFutureTask<X> task = new DeferredFutureTask(new DatabaseTask(), new DatabaseCancellationHandler());
dm.when(task).done(...)You can also easily use with Groovy!
@Grab('org.jdeferred.v2:jdeferred-core:2.0.0')
import org.jdeferred2.*
import org.jdeferred2.impl.*
def deferred = new DeferredObject()
def promise = deferred.promise()
promise.done { result ->
println "done: $result"
}.fail { rejection ->
println "fail: $rejection"
}.always { state, result, rejection ->
println "always"
}
deferred.resolve("done")Since 1.1.0-Beta1
jdeferred-android is now available, and it can be included just like any other Android libraries!
It also uses Android Maven plugin and builds apklib file. If you use Android Maven plugin, you can include
dependency:
APKLIB with Maven:
<dependency>
<groupId>org.jdeferred.v2</groupId>
<artifactId>jdeferred-android</artifactId>
<version>${version}</version>
<type>apklib</type>
</dependency>AAR with Maven:
Since 1.2.0-Beta1
<dependency>
<groupId>org.jdeferred.v2</groupId>
<artifactId>jdeferred-android-aar</artifactId>
<version>${version}</version>
<type>aar</type>
</dependency>AAR with Gradle:
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}'
// or
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}@aar'Find available versions on Maven Central Repository.
No open issues yet, or sync has not completed.