Custom references
Most of the time working with PraxisCORE you do not need to manage references to objects manually.
However, Ref<T> offers a way to hook into the reference handling lifecycle inside the runtime
when this is required eg. for interacting with other libraries. It provides a safe way
for carrying references across code changes, and determining what happens when code is updated
or the reference deleted.
The reference must be initialized before use, often with a constructor references. Handlers can be
added for onReset() and onDispose() - the former will be called every code change, the latter
when the root is stopped or the reference deleted. If the reference is AutoCloseable then it will
be closed automatically on disposal by default.
Use eg.
@Inject Ref<List<String>> strings;
public void init() {
strings.init(ArrayList::new)
.apply(l -> {
if (l.isEmpty()) {
l.add("A String");
}
});
List<String> lst = strings.get(); // same list across code changes
}
See the Javadoc for Ref<T> included with the IDE for the full range of features.
Ref.Provider
As well as using Ref<T> directly in components, a reference provider can be registered to
handle the configuration of multiple references from one place. The @Inject annotation
supports a provider value. The provider implementation can be a static class or separately
in shared code to manage references across a graph. The field itself
should be of the injected type.
There is also a default reference provider, that allows injecting fields of List, Set
and Map which will inject ArrayList, LinkedHashSet and LinkedHashMap respectively.
package SHARED;
// imports
public class Types extends Ref.Provider {
public Types() {
register(List.class, (Ref<List<?>> r) ->
r.init(LinkedList::new).onReset(List::clear));
}
}
@Inject List<String> arrayList;
@Inject(provider = SHARED.Types.class) List<String> linkedList;
Reference ports
A Ref<T> field can be annotated with @Out to create a reference output port. Input
ports use Ref.Input<T>, which provides a List<T> of values from connected references.
@Out Ref<String> out;
@In Ref.Input<String> in;
public void init() {
List<String> values = in.values();
in.onUpdate(list -> {
if (!list.isEmpty()) {
// do something with inputs
}
});
}
Publish and Subscribe
A Ref<T> field in a container can be marked with @Publish annotation. Any Ref<T> fields
in direct child components can be annotated with @Subscribe and will automatically update
in sync with the container value. Both annotations support an optional name.
@Inject @Ref.Publish
Ref<String> defRef;
@Inject @Ref.Publish(name = "alt")
Ref<String> altRef;
public void init() {
defRef.set("default");
altRef.set("alternate");
}
@Inject @Ref.Subscribe
Ref<String> defRef;
@Inject @Ref.Subscribe(name = "alt")
Ref<String> altRef;
public void init() {
String foo = altRef.orElse("");
// foo == "alternate"
}
Async set
It's possible to set the value of a Ref<T> field using an Async task. Care should be
taken not to capture state of the component in any background task.