Skip to content

Commit 3c636ce

Browse files
author
nicolaiparlog
committed
Merge branch 'hotfix/npe_in_nestings'
2 parents 998aefa + 09ac907 commit 3c636ce

File tree

6 files changed

+97
-7
lines changed

6 files changed

+97
-7
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ License details can be found in the *LICENSE* file in the project's root folder.
2929

3030
Releases are published [on GitHub](https://github.com/CodeFX-org/LibFX/releases). The release notes also contain a link to the artifact in Maven Central and its coordinates.
3131

32-
The current version is [0.2.0](http://search.maven.org/#artifactdetails|org.codefx.libfx|LibFX|0.2.0|jar):
32+
The current version is [0.2.1](http://search.maven.org/#artifactdetails|org.codefx.libfx|LibFX|0.2.1|jar):
3333

3434
**Maven**:
3535

3636
``` XML
3737
<dependency>
3838
<groupId>org.codefx.libfx</groupId>
3939
<artifactId>LibFX</artifactId>
40-
<version>0.2.0</version>
40+
<version>0.2.1</version>
4141
</dependency>
4242
```
4343

4444
**Gradle**:
4545

4646
```
47-
compile 'org.codefx.libfx:LibFX:0.2.0'
47+
compile 'org.codefx.libfx:LibFX:0.2.1'
4848
```
4949

5050
## Development

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.codefx.libfx</groupId>
88
<artifactId>LibFX</artifactId>
9-
<version>0.2.0</version>
9+
<version>0.2.1</version>
1010
<packaging>jar</packaging>
1111

1212
<!-- PROJECT META INFORMATION -->

src/main/java/org/codefx/libfx/nesting/DeepNesting.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ final class DeepNesting<O extends Observable> implements Nesting<O> {
7474

7575
/**
7676
* The values currently held by the observables.
77+
* <p>
78+
* Before the initialization these will be non-null "uninitialized" objects. This is done to distinguish them from
79+
* null values which could be held by the observables.
7780
*/
7881
private final Object[] values;
7982

@@ -120,14 +123,25 @@ public DeepNesting(ObservableValue outerObservable, List<NestingStep> nestingSte
120123
maxLevel = nestingSteps.size();
121124

122125
this.observables = createObservables(outerObservable, maxLevel);
123-
this.values = new Object[maxLevel];
126+
this.values = createUnitializedValues();
124127
this.nestingSteps = nestingSteps.toArray(new NestingStep[maxLevel]);
125128
this.changeListeners = createChangeListeners(maxLevel);
126129
this.inner = new SimpleObjectProperty<>(this, "inner");
127130

128131
initializeNesting();
129132
}
130133

134+
/**
135+
* @return an array of uninitialized values (i.e. non-null values which do not equal any other instances occurring
136+
* "in the wild")
137+
*/
138+
private Object[] createUnitializedValues() {
139+
Object[] values = new Object[maxLevel];
140+
for (int i = 0; i < maxLevel; i++)
141+
values[i] = new Unitialized();
142+
return values;
143+
}
144+
131145
/**
132146
* Creates an initialized array of observables. Its first item is the specified outer observable (its other items
133147
* are null).
@@ -234,8 +248,8 @@ public void initialize() {
234248
* identical and nothing more needs to be updated.
235249
* <p>
236250
* Note that the loop will not stop on null observables and null values. Instead it continues and replaces all
237-
* 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 and have to be replaced.
251+
* stored observables and values with null. This is the desired behavior as the hierarchy is now in an incomplete
252+
* state where the old observables and values are obsolete and have to be replaced.
239253
*/
240254
private class NestingUpdater {
241255

@@ -394,6 +408,13 @@ private void updateInnerObservable() {
394408

395409
}
396410

411+
/**
412+
* Represents an uninitialized entry in the {@link #values} array.
413+
*/
414+
private static class Unitialized {
415+
// no body needed
416+
}
417+
397418
//#end PRIVATE CLASSES
398419

399420
}

src/test/java/org/codefx/libfx/nesting/AbstractDeepNestingTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.codefx.libfx.nesting;
22

33
import static org.codefx.libfx.nesting.testhelper.NestingAccess.getNestingObservable;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertNotNull;
46
import static org.junit.Assert.assertNull;
57
import static org.junit.Assert.assertSame;
68
import javafx.beans.Observable;
@@ -22,6 +24,37 @@ public abstract class AbstractDeepNestingTest<OO extends Observable, IO extends
2224

2325
// #region TESTS
2426

27+
// construction
28+
29+
/**
30+
* Tests whether creating a {@link DeepNesting} on an outer observable which contains null works correctly.
31+
* <p>
32+
* This ensures that a "broken" hierarchy is correctly initialized.
33+
*/
34+
@Test
35+
public void testCreatingWhenOuterObservableHasValueNull() {
36+
outerObservable = createNewNestingHierarchyWhereOuterObservableHasNullValue();
37+
nesting = createNewNestingFromOuterObservable(outerObservable);
38+
39+
assertNotNull(nesting.innerObservableProperty().getValue());
40+
assertFalse(nesting.innerObservableProperty().getValue().isPresent());
41+
}
42+
43+
/**
44+
* Tests whether creating a {@link DeepNesting} on a hierarchy where on of the nested observables contains null
45+
* works correctly.
46+
* <p>
47+
* This ensures that a "broken" hierarchy is correctly initialized.
48+
*/
49+
@Test
50+
public void testCreatingWhenNestedObservableHasValueNull() {
51+
outerObservable = createNewNestingHierarchyWhereNestedObservableHasNullValue();
52+
nesting = createNewNestingFromOuterObservable(outerObservable);
53+
54+
assertNotNull(nesting.innerObservableProperty().getValue());
55+
assertFalse(nesting.innerObservableProperty().getValue().isPresent());
56+
}
57+
2558
// nested value
2659

2760
/**
@@ -90,6 +123,21 @@ public void testWhenSettingOuterValueToNull() {
90123

91124
// #region ABSTRACT METHODS
92125

126+
/**
127+
* Creates a new outer observable with a null value. The returned instances must be new for each call.
128+
*
129+
* @return an {@link ObservableValue} containing null
130+
*/
131+
protected abstract OO createNewNestingHierarchyWhereOuterObservableHasNullValue();
132+
133+
/**
134+
* Creates a new nesting hierarchy where one of the nested observables contains null and returns the outer
135+
* observable. All returned instances must be new for each call.
136+
*
137+
* @return an {@link ObservableValue} containing the outer value of a nesting hierarchy
138+
*/
139+
protected abstract OO createNewNestingHierarchyWhereNestedObservableHasNullValue();
140+
93141
/**
94142
* Sets a new value of the specified kind on the specified level of the nesting hierarchy contained in the specified
95143
* outer observable.

src/test/java/org/codefx/libfx/nesting/AbstractDeepNestingTestForDefaultNesting.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ protected Property<OuterValue> createNewNestingHierarchy() {
2828
return new SimpleObjectProperty<>(outer);
2929
}
3030

31+
@Override
32+
protected Property<OuterValue> createNewNestingHierarchyWhereOuterObservableHasNullValue() {
33+
return new SimpleObjectProperty<>(null);
34+
}
35+
36+
@Override
37+
protected Property<OuterValue> createNewNestingHierarchyWhereNestedObservableHasNullValue() {
38+
OuterValue outer = OuterValue.createWithNull();
39+
return new SimpleObjectProperty<>(outer);
40+
}
41+
3142
@Override
3243
protected void setNewValue(Property<OuterValue> outerObservable, Level level, Value kindOfNewValue) {
3344

src/test/java/org/codefx/libfx/nesting/AbstractNestingTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ public void setUp() {
4444

4545
// #region TESTS
4646

47+
// construction
48+
49+
/**
50+
* Tests whether creating a nesting with on a null outer observable throws an exception.
51+
*/
52+
@Test(expected = NullPointerException.class)
53+
public void testExceptionWhenNullObservable() {
54+
nesting = createNewNestingFromOuterObservable(null);
55+
}
56+
4757
/**
4858
* Tests whether the {@link #nesting}'s {@link Nesting#innerObservableProperty() innerObservable} property contains
4959
* the correct observable, which is the {@link #outerObservable}'s inner observable.

0 commit comments

Comments
 (0)