项目作者: tomtzook

项目描述 :
Java beans and observables
高级语言: Java
项目地址: git://github.com/tomtzook/JavaBeans.git
创建时间: 2018-08-24T10:04:25Z
项目社区:https://github.com/tomtzook/JavaBeans

开源协议:Apache License 2.0

下载


JavaBeans

Maven Central
Travis (.org) branch
GitHub

Library providing java beans utilities and observables.
Provides interfaces and several implementations for properties, observable data and such.

Building

Simply run ./gradlew build from the main directory.
This will build the library and export it along with a sources jar and javadoc archive into build/libs.

Properties

JavaBeans introduces the Property interface, which is a mutable value, extending upon
Java‘s java.uti.function.Supplier interface.

Basic properties, which implement Property expose set and get to modify the internal
their value:

  1. Property<String> prop = ...
  2. prop.set("Hello World");
  3. System.out.println(prop.get()); // returns "Hello World"

There is no restrictions on how implementations store and access values, so make
sure to check which implementation you use and whether or not it fits your needs.

Specialized Properties

In addition to the basic interface, there are also specializations for primitive
types: long, int, boolean, double. Each specialization still exports set and get
as it extends the base Property interface, however those methods return a wrapper class.
To get a primitive type, use getAsType and setAsType where Type is replaced by the
primitive type, e.g. getAsBoolean, getAsInt etc. It is recommended to use those methods.

  1. IntProperty prop = ...
  2. prop.setAsInt(12);
  3. System.out.println(prop.getAsInt()); // returns 12

The set methods do not accept null values in specialization implementations.

Implementations

JavaBeans provides the following implementations for Property, each implementation exists for
the specializations as well:

  • Simple: an in-memory implementation which is not thread-safe. Under com.beans.properties
  • Atomic: an in-memory thread-safe implementation. Under com.beans.properties.atomic

Observables

An ObservableValue is a value which can be observed for changes using listeners. Based
on the java.util.function.Supplier interface.

An ObservableProperty is a property which can be observed for changes using listeners.
Based on the Property and ObservableValue interfaces.

Both have primitive specializations for types: long, int, boolean, double.

Creation of such properties should be done using ObservableFactory.

Listeners

Users may register ChangeListeners to an observable.
Any changes to that observable‘s value will
cause an invocation of the listener with ChangeEvent.

  1. ObservableIntProperty prop = ....
  2. prop.addChangeListener((e)-> {
  3. System.out.println("New value: " + e.getNewValue())
  4. });

Binding

Binding Observables will connect them. It is only possible between 2 Observables with
similar types. There are 2 types of bindings:

  • Single-Directional binding, o1.bind(o2) will connect the value of observable
    o1 to o2, such that any changes to o2 will change the value of o1. However,
    changing the value of o1 directly, with setValue will not be allowed, causing
    a RuntimeException.
    ```Java
    ObservableIntProperty prop1 = …;
    prop1.set(2);
    ObservableIntProperty prop2 = …;
    prop2.set(10);

System.out.println(prop1.get()); // returns 2

prop1.bind(prop2);
System.out.println(prop1.get()); // returns 10

prop2.set(100);
System.out.println(prop1.get()); // returns 100
System.out.println(prop2.get()); // returns 100

prop1.set(5); // throws IllegalStateException

  1. - Bi-Directional binding, `o1.bindBidirectional(o2)` will connect the value of observable
  2. `o1` to `o2`, such that any changes to `o2` will change the value of `o1`, and changes to `o1`
  3. will change `o2`.
  4. ```Java
  5. ObservableIntProperty prop1 = ...;
  6. prop1.set(2);
  7. ObservableIntProperty prop2 = ...;
  8. prop2.set(10);
  9. System.out.println(prop1.get()); // returns 2
  10. prop1.bindBidirectional(prop2);
  11. System.out.println(prop1.get()); // returns 10
  12. prop2.set(100);
  13. System.out.println(prop1.get()); // returns 100
  14. System.out.println(prop2.get()); // returns 100
  15. prop1.set(5);
  16. System.out.println(prop1.get()); // returns 5
  17. System.out.println(prop2.get()); // returns 5

While bound, properties will still invoke listeners on changes.

Observable From Supplier

Using PollingObserableFactory, it is possible to create ObservableValues out of Suppliers
(including specializations).

Create the factory first:

  1. ObserableFactory observableFactory = ...;
  2. ScheduledExecutorService executorService = ...;
  3. int pollingTimeMs = 25;
  4. PollingObserableFactory factory = new PollingObserableFactory(observableFactory, executorService, pollingTimeMs);

And simply use factory.from to create the ObservableValue. Now, it will be possible to listen
to changes of the Supplier and bind it to other observables.

  1. Supplier<String> supplier = ...;
  2. ObservableValue<String> observable = factory.from(supplier);

The ScheduledExecutorService will be used to poll updates from the supplier and test for changes in the value,
making it observable. The pollingTimeMs is the period for polling the supplier.

Global

For easier work with the observable factories, use the Observables class. This class will
automatically create the factories and provide access to them:

  1. ObservableIntProperty prop = Observables.factory().newIntProperty();
  2. Supplier<Object> supplier = ...;
  3. ObserableValue<Object> observable = Observables.pollingFactory().from(supplier);

The created factories will use a ScheduledExecutorService created specifically for dispatching events
and for polling suppliers. This executor service will be terminated automatically using a shutdown hook.

It is also possible to configure the factories manually instead of using the automatically created ones. This should
be done before any usage or access to the factories:

  1. ObservableFactory factory = ...;
  2. Obserables.setFactory(factory);
  3. ObservablePollingFactory pollingFactory = ...;
  4. Obserables.setPollingFactory(pollingFactory);

It is also possible to configure the ScheduledExecutorService that will be used by the factories,
using setExecutorService. Doing so will make the factories use that executor service, but should be done
before any usage/access to the factories. The executor service will not be terminated automatically, and
this must be the responsibility of the user providing the instance.