Skip to content

Commit f65b7c0

Browse files
author
Nicolai Parlog
committed
'Nesting.innerObservable' now contains an 'Optional' of the nested observable to make clear that is might be null.
1 parent db4e766 commit f65b7c0

11 files changed

+109
-57
lines changed

src/org/codefx/nesting/AbstractNestingBuilder.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5+
import java.util.Objects;
56
import java.util.function.Function;
67

78
import javafx.beans.Observable;
@@ -58,6 +59,8 @@ abstract class AbstractNestingBuilder<T, O extends Observable> {
5859
* the outer observable upon which the constructed nesting depends
5960
*/
6061
protected AbstractNestingBuilder(O outerObservable) {
62+
Objects.requireNonNull(outerObservable, "The argument 'outerObservable' must not be null.");
63+
6164
this.outerObservable = outerObservable;
6265
this.previousBuilder = null;
6366
this.nestingStep = null;
@@ -77,6 +80,9 @@ protected AbstractNestingBuilder(O outerObservable) {
7780
protected <P> AbstractNestingBuilder(
7881
AbstractNestingBuilder<P, ?> previousBuilder, NestingStep<P, ? extends O> nestingStep) {
7982

83+
Objects.requireNonNull(previousBuilder, "The argument 'previousBuilder' must not be null.");
84+
Objects.requireNonNull(nestingStep, "The argument 'nestingStep' must not be null.");
85+
8086
this.outerObservable = null;
8187
this.previousBuilder = previousBuilder;
8288
this.nestingStep = nestingStep;
@@ -122,21 +128,21 @@ private NestingConstructionKit createNestingConstructionKit() {
122128
}
123129

124130
/**
125-
* Fills the specified kit with an observable value and all observable getters which were given to this and its
126-
* previous nesting builders.
131+
* Fills the specified kit with an observable value and all nesting steps which were given to this and its previous
132+
* nesting builders. The steps' order is from outer to inner property and hence is correct for the constructor of
133+
* {@link DeepNesting}.
127134
*
128135
* @param kit
129136
* the {@link NestingConstructionKit} to fill with an {@link #outerObservable} and {@link #nestingStep
130-
* nestedObservableGetters}
137+
* nestingSteps}
131138
*/
132139
@SuppressWarnings("rawtypes")
133140
private void fillNestingConstructionKit(NestingConstructionKit kit) {
134141

135142
/*
136143
* Uses recursion to move up the chain of 'previousNestedBuilder's until the outer builder is reached. This
137144
* builder's 'outerObservable' is set to the specified 'kit'. The 'kit's list of nesting steps is then filled
138-
* when the recursion is closed, i.e. top down from the outermost builder to the inner one. This creates the
139-
* list on the correct order for the 'Nesting' constructor.
145+
* when the recursion is closed, i.e. top down from the outermost builder to the inner one.
140146
*/
141147

142148
if (isOuterBuilder())

src/org/codefx/nesting/AbstractNestingNestingBuilder.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ protected <P> AbstractNestingNestingBuilder(AbstractNestingBuilder<P, ?> previou
5757
* the function which performs the nesting step from one observable to the next
5858
* @return an {@link ObservableValueNestingBuilder} which builds a nesting from this builder's settings and the
5959
* specified nesting steps
60-
* @throws NullPointerException
61-
* if the specified function is null
6260
*/
6361
public <N> ObservableValueNestingBuilder<N> nestObservable(NestingStep<T, ObservableValue<N>> nestingStep) {
6462
Objects.requireNonNull(nestingStep, "The argument 'nestingStep' must not be null.");
@@ -75,8 +73,6 @@ public <N> ObservableValueNestingBuilder<N> nestObservable(NestingStep<T, Observ
7573
* the function which performs the nesting step from one observable to the next
7674
* @return an {@link ObservableValueNestingBuilder} which builds a nesting from this builder's settings and the
7775
* specified nesting steps
78-
* @throws NullPointerException
79-
* if the specified function is null
8076
*/
8177
public <N> ObjectPropertyNestingBuilder<N> nestProperty(NestingStep<T, Property<N>> nestingStep) {
8278
Objects.requireNonNull(nestingStep, "The argument 'nestingStep' must not be null.");

src/org/codefx/nesting/DeepNesting.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44
import java.util.Objects;
5+
import java.util.Optional;
56

67
import javafx.beans.Observable;
78
import javafx.beans.property.Property;
@@ -84,7 +85,7 @@ final class DeepNesting<O extends Observable> implements Nesting<O> {
8485
/**
8586
* The property holding the current innermost observable.
8687
*/
87-
private final Property<O> inner;
88+
private final Property<Optional<O>> inner;
8889

8990
//#end PROPERTIES
9091

@@ -107,8 +108,6 @@ final class DeepNesting<O extends Observable> implements Nesting<O> {
107108
* </ul>
108109
* These conditions are not checked by the compiler nor during construction. Violations will later lead
109110
* to {@link ClassCastException ClassCastExceptions}.
110-
* @throws NullPointerException
111-
* if any of the arguments is null
112111
* @throws IllegalArgumentException
113112
* if the list is empty
114113
*/
@@ -124,7 +123,7 @@ public DeepNesting(ObservableValue outerObservable, List<NestingStep> nestingSte
124123
this.values = new Object[maxLevel];
125124
this.nestingSteps = nestingSteps.toArray(new NestingStep[maxLevel]);
126125
this.changeListeners = createChangeListeners(maxLevel);
127-
this.inner = new SimpleObjectProperty<O>(this, "inner");
126+
this.inner = new SimpleObjectProperty<>(this, "inner");
128127

129128
initializeNesting();
130129
}
@@ -161,8 +160,6 @@ private ChangeListener[] createChangeListeners(int levels) {
161160
return listeners;
162161
}
163162

164-
//#end CONSTRUCTION
165-
166163
/**
167164
* Initializes this nesting by filling the arrays {@link #observables} and {@link #values} and adding the
168165
* corresponding {@link #changeListeners changeListener} to each observable.
@@ -171,6 +168,8 @@ private void initializeNesting() {
171168
new NestingInitializer().initialize();
172169
}
173170

171+
//#end CONSTRUCTION
172+
174173
/**
175174
* Updates the nesting from the specified level on. This includes moving listeners from old to new observables and
176175
* updating the arrays {@link #observables} and {@link #values}.
@@ -189,7 +188,7 @@ private void updateNestingFromLevel(int startLevel) {
189188
* {@inheritDoc}
190189
*/
191190
@Override
192-
public ReadOnlyProperty<O> innerObservable() {
191+
public ReadOnlyProperty<Optional<O>> innerObservable() {
193192
return inner;
194193
}
195194

@@ -235,7 +234,7 @@ public void initialize() {
235234
* identical and nothing more needs to be updated. <br>
236235
* Note that the loop will not stop on null observables and null values. Instead it continues and replaces all
237236
* stored observables and values with null. This is the desired behavior as the hierarchy is in now an incomplete
238-
* state and the old observables and values are obsolete.
237+
* state and the old observables and values are obsolete and have to be replaced.
239238
*/
240239
private class NestingUpdater {
241240

@@ -386,8 +385,10 @@ private void moveToNextLevel() {
386385
private void updateInnerObservable() {
387386
// if the loop encountered a level where the stored and the current value are identical,
388387
// all higher levels are identical as well and the inner observable can not have changed
389-
if (currentLevelIsInnerLevel)
390-
inner.setValue((O) innerObservable);
388+
if (currentLevelIsInnerLevel) {
389+
Optional innerObservableOptional = Optional.ofNullable(innerObservable);
390+
inner.setValue(innerObservableOptional);
391+
}
391392
}
392393

393394
}

src/org/codefx/nesting/Nesting.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package org.codefx.nesting;
22

3+
import java.util.Optional;
4+
35
import javafx.beans.Observable;
46
import javafx.beans.property.ReadOnlyProperty;
57
import javafx.beans.value.ObservableValue;
68

79
/**
810
* A nesting encapsulates a hierarchy of nested {@link ObservableValue ObservableValues}; its {@link #innerObservable()}
9-
* always contains the current innermost {@link Observable} in that hierarchy. If some observable or its value were
10-
* null, {@code innerObservable} contains null as well.
11+
* always contains the current innermost {@link Observable} in that hierarchy as an {@link Optional}. If some observable
12+
* or its value were null, {@code innerObservable} contains {@link Optional#empty()}.
1113
* <p>
1214
* Nestings will usually be implemented such that they eagerly evaluate the nested observables.
1315
*
@@ -22,6 +24,6 @@ public interface Nesting<O extends Observable> {
2224
*
2325
* @return the innermost {@link ObservableValue}
2426
*/
25-
ReadOnlyProperty<O> innerObservable();
27+
ReadOnlyProperty<Optional<O>> innerObservable();
2628

2729
}

src/org/codefx/nesting/Nestings.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* O(outer) and N(ested)
1515
* <p>
1616
* TODO examples; differences between builder types
17+
* <p>
18+
* TODO comment about nulls (here?)
1719
*/
1820
public class Nestings {
1921

src/org/codefx/nesting/ShallowNesting.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.codefx.nesting;
22

33
import java.util.Objects;
4+
import java.util.Optional;
45

56
import javafx.beans.Observable;
67
import javafx.beans.property.ReadOnlyProperty;
@@ -18,7 +19,7 @@ final class ShallowNesting<O extends Observable> implements Nesting<O> {
1819
* The property holding the current inner observable, which is always the outer observable specified during
1920
* construction.
2021
*/
21-
private final ReadOnlyProperty<O> inner;
22+
private final ReadOnlyProperty<Optional<O>> inner;
2223

2324
/**
2425
* Creates a new shallow nesting whose {@link #innerObservable} property always holds the specified outer
@@ -29,11 +30,12 @@ final class ShallowNesting<O extends Observable> implements Nesting<O> {
2930
*/
3031
public ShallowNesting(O outerObservable) {
3132
Objects.requireNonNull(outerObservable, "The argument 'outerObservable' must not be null.");
32-
inner = new SimpleObjectProperty<O>(this, "inner", outerObservable);
33+
Optional<O> optionalInner = Optional.of(outerObservable);
34+
inner = new SimpleObjectProperty<>(this, "inner", optionalInner);
3335
}
3436

3537
@Override
36-
public ReadOnlyProperty<O> innerObservable() {
38+
public ReadOnlyProperty<Optional<O>> innerObservable() {
3739
return inner;
3840
}
3941

src/org/codefx/nesting/property/AbstractNestedPropertyBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ abstract class AbstractNestedPropertyBuilder<N extends Property<?>, P extends Ne
4545
* the nesting which will be used for all nested properties
4646
*/
4747
protected AbstractNestedPropertyBuilder(Nesting<N> nesting) {
48+
Objects.requireNonNull(nesting, "The argument 'nesting' must not be null.");
4849
this.nesting = nesting;
4950
}
5051

src/org/codefx/nesting/property/NestedIntegerProperty.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.codefx.nesting.property;
22

3+
import java.util.Objects;
4+
35
import javafx.beans.property.BooleanProperty;
46
import javafx.beans.property.IntegerProperty;
57
import javafx.beans.property.Property;
@@ -31,12 +33,13 @@ public class NestedIntegerProperty extends SimpleIntegerProperty implements Nest
3133
* @param nesting
3234
* the nesting this property is based on
3335
* @param bean
34-
* the bean which owns this property
36+
* the bean which owns this property; can be null
3537
* @param name
36-
* this property's name
38+
* this property's name; can be null
3739
*/
3840
NestedIntegerProperty(Nesting<? extends Property<Number>> nesting, Object bean, String name) {
3941
super(bean, name);
42+
Objects.requireNonNull(nesting, "The argument 'nesting' must not be null.");
4043
this.innerObservableNull = new SimpleBooleanProperty(this, "innerObservableNull");
4144

4245
PropertyToNestingBinding.bind(this, isNull -> innerObservableNull.set(isNull), nesting);

src/org/codefx/nesting/property/NestedObjectProperty.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.codefx.nesting.property;
22

3+
import java.util.Objects;
4+
35
import javafx.beans.property.BooleanProperty;
46
import javafx.beans.property.ObjectProperty;
57
import javafx.beans.property.Property;
@@ -11,7 +13,7 @@
1113

1214
/**
1315
* An {@link ObjectProperty} which also implements {@link NestedProperty}.
14-
*
16+
*
1517
* @param <T>
1618
* the type of the value wrapped by this property
1719
*/
@@ -34,12 +36,13 @@ public class NestedObjectProperty<T> extends SimpleObjectProperty<T> implements
3436
* @param nesting
3537
* the nesting this property is based on
3638
* @param bean
37-
* the bean which owns this property
39+
* the bean which owns this property; can be null
3840
* @param name
39-
* this property's name
41+
* this property's name; can be null
4042
*/
4143
NestedObjectProperty(Nesting<? extends Property<T>> nesting, Object bean, String name) {
4244
super(bean, name);
45+
Objects.requireNonNull(nesting, "The argument 'nesting' must not be null.");
4346
this.innerObservableNull = new SimpleBooleanProperty(this, "innerObservableNull");
4447

4548
PropertyToNestingBinding.bind(this, isNull -> innerObservableNull.set(isNull), nesting);

src/org/codefx/nesting/property/PropertyToNestingBinding.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,10 @@ public static <T> void bind(
9797
*/
9898
private void bindToNestingProperty() {
9999
// bind to the nesting's current property
100-
moveBinding(Optional.empty(), Optional.ofNullable(nesting.innerObservable().getValue()));
100+
moveBinding(Optional.empty(), nesting.innerObservable().getValue());
101101
// add a listener to the nesting which moves the binding from one property to the next
102102
nesting.innerObservable().addListener(
103-
(observable, oldProperty, newProperty) -> {
104-
Optional<Property<T>> oldPropertyOpt = Optional.ofNullable(oldProperty);
105-
Optional<Property<T>> newPropertyOpt = Optional.ofNullable(newProperty);
106-
moveBinding(oldPropertyOpt, newPropertyOpt);
107-
});
103+
(observable, oldProperty, newProperty) -> moveBinding(oldProperty, newProperty));
108104
}
109105

110106
/**
@@ -115,7 +111,8 @@ private void bindToNestingProperty() {
115111
* @param newPropertyOpt
116112
* the {@link Property} to which to bind
117113
*/
118-
private void moveBinding(Optional<Property<T>> oldPropertyOpt, Optional<Property<T>> newPropertyOpt) {
114+
private void moveBinding(Optional<? extends Property<T>> oldPropertyOpt,
115+
Optional<? extends Property<T>> newPropertyOpt) {
119116
oldPropertyOpt.ifPresent(oldProperty -> nestedProperty.unbindBidirectional(oldProperty));
120117
newPropertyOpt.ifPresent(newProperty -> nestedProperty.bindBidirectional(newProperty));
121118

0 commit comments

Comments
 (0)