Skip to content

Commit

Permalink
Merge branch 'hotfix/npe_in_nestings'
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolaiparlog committed May 1, 2015
2 parents 998aefa + 09ac907 commit 3c636ce
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 7 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,22 @@ License details can be found in the *LICENSE* file in the project's root folder.

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.

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

**Maven**:

``` XML
<dependency>
<groupId>org.codefx.libfx</groupId>
<artifactId>LibFX</artifactId>
<version>0.2.0</version>
<version>0.2.1</version>
</dependency>
```

**Gradle**:

```
compile 'org.codefx.libfx:LibFX:0.2.0'
compile 'org.codefx.libfx:LibFX:0.2.1'
```

## Development
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.codefx.libfx</groupId>
<artifactId>LibFX</artifactId>
<version>0.2.0</version>
<version>0.2.1</version>
<packaging>jar</packaging>

<!-- PROJECT META INFORMATION -->
Expand Down
27 changes: 24 additions & 3 deletions src/main/java/org/codefx/libfx/nesting/DeepNesting.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ final class DeepNesting<O extends Observable> implements Nesting<O> {

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

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

this.observables = createObservables(outerObservable, maxLevel);
this.values = new Object[maxLevel];
this.values = createUnitializedValues();
this.nestingSteps = nestingSteps.toArray(new NestingStep[maxLevel]);
this.changeListeners = createChangeListeners(maxLevel);
this.inner = new SimpleObjectProperty<>(this, "inner");

initializeNesting();
}

/**
* @return an array of uninitialized values (i.e. non-null values which do not equal any other instances occurring
* "in the wild")
*/
private Object[] createUnitializedValues() {
Object[] values = new Object[maxLevel];
for (int i = 0; i < maxLevel; i++)
values[i] = new Unitialized();
return values;
}

/**
* Creates an initialized array of observables. Its first item is the specified outer observable (its other items
* are null).
Expand Down Expand Up @@ -234,8 +248,8 @@ public void initialize() {
* identical and nothing more needs to be updated.
* <p>
* Note that the loop will not stop on null observables and null values. Instead it continues and replaces all
* stored observables and values with null. This is the desired behavior as the hierarchy is in now an incomplete
* state and the old observables and values are obsolete and have to be replaced.
* stored observables and values with null. This is the desired behavior as the hierarchy is now in an incomplete
* state where the old observables and values are obsolete and have to be replaced.
*/
private class NestingUpdater {

Expand Down Expand Up @@ -394,6 +408,13 @@ private void updateInnerObservable() {

}

/**
* Represents an uninitialized entry in the {@link #values} array.
*/
private static class Unitialized {
// no body needed
}

//#end PRIVATE CLASSES

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.codefx.libfx.nesting;

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

// #region TESTS

// construction

/**
* Tests whether creating a {@link DeepNesting} on an outer observable which contains null works correctly.
* <p>
* This ensures that a "broken" hierarchy is correctly initialized.
*/
@Test
public void testCreatingWhenOuterObservableHasValueNull() {
outerObservable = createNewNestingHierarchyWhereOuterObservableHasNullValue();
nesting = createNewNestingFromOuterObservable(outerObservable);

assertNotNull(nesting.innerObservableProperty().getValue());
assertFalse(nesting.innerObservableProperty().getValue().isPresent());
}

/**
* Tests whether creating a {@link DeepNesting} on a hierarchy where on of the nested observables contains null
* works correctly.
* <p>
* This ensures that a "broken" hierarchy is correctly initialized.
*/
@Test
public void testCreatingWhenNestedObservableHasValueNull() {
outerObservable = createNewNestingHierarchyWhereNestedObservableHasNullValue();
nesting = createNewNestingFromOuterObservable(outerObservable);

assertNotNull(nesting.innerObservableProperty().getValue());
assertFalse(nesting.innerObservableProperty().getValue().isPresent());
}

// nested value

/**
Expand Down Expand Up @@ -90,6 +123,21 @@ public void testWhenSettingOuterValueToNull() {

// #region ABSTRACT METHODS

/**
* Creates a new outer observable with a null value. The returned instances must be new for each call.
*
* @return an {@link ObservableValue} containing null
*/
protected abstract OO createNewNestingHierarchyWhereOuterObservableHasNullValue();

/**
* Creates a new nesting hierarchy where one of the nested observables contains null and returns the outer
* observable. All returned instances must be new for each call.
*
* @return an {@link ObservableValue} containing the outer value of a nesting hierarchy
*/
protected abstract OO createNewNestingHierarchyWhereNestedObservableHasNullValue();

/**
* Sets a new value of the specified kind on the specified level of the nesting hierarchy contained in the specified
* outer observable.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ protected Property<OuterValue> createNewNestingHierarchy() {
return new SimpleObjectProperty<>(outer);
}

@Override
protected Property<OuterValue> createNewNestingHierarchyWhereOuterObservableHasNullValue() {
return new SimpleObjectProperty<>(null);
}

@Override
protected Property<OuterValue> createNewNestingHierarchyWhereNestedObservableHasNullValue() {
OuterValue outer = OuterValue.createWithNull();
return new SimpleObjectProperty<>(outer);
}

@Override
protected void setNewValue(Property<OuterValue> outerObservable, Level level, Value kindOfNewValue) {

Expand Down
10 changes: 10 additions & 0 deletions src/test/java/org/codefx/libfx/nesting/AbstractNestingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ public void setUp() {

// #region TESTS

// construction

/**
* Tests whether creating a nesting with on a null outer observable throws an exception.
*/
@Test(expected = NullPointerException.class)
public void testExceptionWhenNullObservable() {
nesting = createNewNestingFromOuterObservable(null);
}

/**
* Tests whether the {@link #nesting}'s {@link Nesting#innerObservableProperty() innerObservable} property contains
* the correct observable, which is the {@link #outerObservable}'s inner observable.
Expand Down

0 comments on commit 3c636ce

Please sign in to comment.