Skip to content

Commit ec64891

Browse files
author
Nicolai Parlog
committed
Continued implementation of nestings:
* builders are now separated by the inner observable * implemented shallow nesting * defined types for nested properties * defined behavior for nested properties when inner observable is null * improved tests for nested properties
1 parent d62a5e4 commit ec64891

37 files changed

+2033
-931
lines changed

.settings/org.eclipse.jdt.core.prefs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_
4545
org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
4646
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=enabled
4747
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
48-
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=default
48+
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
4949
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
5050
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
5151
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
package org.codefx.nesting;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.function.Function;
6+
7+
import javafx.beans.Observable;
8+
import javafx.beans.value.ObservableValue;
9+
10+
/**
11+
* A superclass for builders for all kinds of nested functionality. Holds the nesting hierarchy (outer observable and
12+
* nesting steps) and can build a {@link Nesting} from it.
13+
* <p>
14+
* Subclasses must not allow nesting if type parameter {@code O} does not also implement {@link ObservableValue}! (Which
15+
* wouldn't make sense, anyhow, because then no value would be available for the nesting step.)
16+
*
17+
* @param <T>
18+
* the type of the wrapped value
19+
* @param <O>
20+
* the type of observable this builder can build;
21+
*/
22+
abstract class AbstractNestingBuilder<T, O extends Observable> {
23+
24+
/*
25+
* A builder can either be the outer or a nested builder of a nesting. In the first case, 'outerObservable' is
26+
* non-null, in the second case 'previousBuilder' and 'nestedGetter' are non-null. The method 'isOuterBuilder()'
27+
* indicates which kind of builder this is.
28+
*/
29+
30+
//#region PROPERTIES
31+
32+
/**
33+
* The outer observable upon which all nestings depend. This is only non-null for the outer builder (indicated by
34+
* {@link #isOuterBuilder()}). All others have a {@link #previousBuilder} and a {@link #nestingStep}.
35+
*/
36+
private final O outerObservable;
37+
38+
/**
39+
* The previous builder upon which this builder depends. This is only non-null for nested builders (indicated by
40+
* {@link #isOuterBuilder()}).
41+
*/
42+
private final AbstractNestingBuilder<?, ?> previousBuilder;
43+
44+
/**
45+
* The function which performs the {@link NestingStep} from an instance of the previous builder's wrapped type to
46+
* the next observable. This is only non-null for nested builders (indicated by {@link #isOuterBuilder()}).
47+
*/
48+
private final NestingStep<?, ? extends O> nestingStep;
49+
50+
//#end PROPERTIES
51+
52+
//#region CONSTRUCTION
53+
54+
/**
55+
* Creates a new nesting builder which acts as the outer builder, i.e. has the specified {@link #outerObservable} .
56+
*
57+
* @param outerObservable
58+
* the outer observable upon which the constructed nesting depends
59+
*/
60+
protected AbstractNestingBuilder(O outerObservable) {
61+
this.outerObservable = outerObservable;
62+
this.previousBuilder = null;
63+
this.nestingStep = null;
64+
}
65+
66+
/**
67+
* Creates a new nesting builder which acts as a nested builder, i.e. has the specified {@link #previousBuilder} and
68+
* {@link #nestingStep}.
69+
*
70+
* @param <P>
71+
* the type the previous builder wraps
72+
* @param previousBuilder
73+
* the previous builder
74+
* @param nestingStep
75+
* the function which performs the nesting step from one observable to the next
76+
*/
77+
protected <P> AbstractNestingBuilder(
78+
AbstractNestingBuilder<P, ?> previousBuilder, NestingStep<P, ? extends O> nestingStep) {
79+
80+
this.outerObservable = null;
81+
this.previousBuilder = previousBuilder;
82+
this.nestingStep = nestingStep;
83+
}
84+
85+
//#end CONSTRUCTION
86+
87+
// #region BUILD
88+
89+
/**
90+
* Creates a new nesting from this builder's settings. This method can be called arbitrarily often and each call
91+
* returns a new instance.
92+
*
93+
* @return a new instance of {@link Nesting}
94+
*/
95+
public Nesting<O> buildNesting() {
96+
if (isOuterBuilder())
97+
return new ShallowNesting<>(outerObservable);
98+
99+
// create a construction kit and use it to create a deep nesting
100+
NestingConstructionKit kit = createNestingConstructionKit();
101+
return new DeepNesting<>(kit.getOuterObservable(), kit.getNestingSteps());
102+
}
103+
104+
/**
105+
* Indicates whether this builder is the outer builder.
106+
*
107+
* @return true if this is the outer builder
108+
*/
109+
private boolean isOuterBuilder() {
110+
return outerObservable != null;
111+
}
112+
113+
/**
114+
* Returns a nesting construction kit based in this builder's current settings.
115+
*
116+
* @return an instance of {@link NestingConstructionKit}
117+
*/
118+
private NestingConstructionKit createNestingConstructionKit() {
119+
NestingConstructionKit kit = new NestingConstructionKit();
120+
fillNestingConstructionKit(kit);
121+
return kit;
122+
}
123+
124+
/**
125+
* Fills the specified kit with an observable value and all observable getters which were given to this and its
126+
* previous nesting builders.
127+
*
128+
* @param kit
129+
* the {@link NestingConstructionKit} to fill with an {@link #outerObservable} and {@link #nestingStep
130+
* nestedObservableGetters}
131+
*/
132+
@SuppressWarnings("rawtypes")
133+
private void fillNestingConstructionKit(NestingConstructionKit kit) {
134+
135+
/*
136+
* Uses recursion to move up the chain of 'previousNestedBuilder's until the outer builder is reached. This
137+
* 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.
140+
*/
141+
142+
if (isOuterBuilder())
143+
/*
144+
* This class' contract states that nesting must not occur when the outerObservable's type O is not also an
145+
* 'ObservableValue'.
146+
*/
147+
kit.setOuterObservable((ObservableValue) outerObservable);
148+
else {
149+
previousBuilder.fillNestingConstructionKit(kit);
150+
kit.getNestingSteps().add(nestingStep);
151+
}
152+
}
153+
154+
//#end BUILD
155+
156+
// #region PRIVATE CLASSES
157+
158+
/**
159+
* An editable class which can be used to collect all instances needed to call
160+
* {@link DeepNesting#DeepNesting(ObservableValue, List) new Nesting(...)}.
161+
*/
162+
@SuppressWarnings("rawtypes")
163+
protected static class NestingConstructionKit {
164+
165+
// #region PROPERTIES
166+
167+
/**
168+
* The outer {@link ObservableValue}
169+
*/
170+
private ObservableValue outerObservable;
171+
172+
/**
173+
* The list of functions which perform the {@link NestingStep NestingSteps} from one {@link ObservableValue
174+
* observable} to the next.
175+
*/
176+
private final List<NestingStep> nestingSteps;
177+
178+
//#end PROPERTIES
179+
180+
// #region CONSTRUCTOR
181+
182+
/**
183+
* Creates a new empty construction kit.
184+
*/
185+
public NestingConstructionKit() {
186+
nestingSteps = new ArrayList<>();
187+
}
188+
189+
//#end CONSTRUCTOR
190+
191+
// #region PROPERTY ACCESS
192+
193+
/**
194+
* @return the outer {@link ObservableValue}
195+
*/
196+
public ObservableValue getOuterObservable() {
197+
return outerObservable;
198+
}
199+
200+
/**
201+
* Sets the new outer observable value.
202+
*
203+
* @param outerObservable
204+
* the outer {@link ObservableValue} to set
205+
*/
206+
public void setOuterObservable(ObservableValue outerObservable) {
207+
this.outerObservable = outerObservable;
208+
}
209+
210+
/**
211+
* @return the list of {@link Function Functions} which get the nested {@link ObservableValue observables}
212+
*/
213+
public List<NestingStep> getNestingSteps() {
214+
return nestingSteps;
215+
}
216+
217+
//#end PROPERTY ACCESS
218+
219+
}
220+
221+
//#end PRIVATE CLASSES
222+
223+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.codefx.nesting;
2+
3+
import java.util.Objects;
4+
5+
import javafx.beans.property.IntegerProperty;
6+
import javafx.beans.property.Property;
7+
import javafx.beans.value.ObservableValue;
8+
9+
/**
10+
* An {@link AbstractNestingBuilder} which allows further nesting.
11+
*
12+
* @param <T>
13+
* the type of the wrapped value
14+
* @param <O>
15+
* the type of observable this builder can build
16+
*/
17+
abstract class AbstractNestingNestingBuilder<T, O extends ObservableValue<T>> extends AbstractNestingBuilder<T, O> {
18+
19+
// #region CONSTRUCTION
20+
21+
/**
22+
* Creates a new nesting builder which acts as the outer builder.
23+
*
24+
* @param outerObservable
25+
* the outer observable upon which the constructed nesting depends
26+
*/
27+
protected AbstractNestingNestingBuilder(O outerObservable) {
28+
super(outerObservable);
29+
}
30+
31+
/**
32+
* Creates a new nesting builder which acts as a nested builder.
33+
*
34+
* @param <P>
35+
* the type the previous builder wraps
36+
* @param previousNestedBuilder
37+
* the previous builder
38+
* @param nestingStep
39+
* the function which performs the nesting step from one observable to the next
40+
*/
41+
protected <P> AbstractNestingNestingBuilder(AbstractNestingBuilder<P, ?> previousNestedBuilder,
42+
NestingStep<P, O> nestingStep) {
43+
super(previousNestedBuilder, nestingStep);
44+
}
45+
46+
//#end CONSTRUCTION
47+
48+
//#region NEST
49+
50+
/**
51+
* Returns a builder for nestings whose inner observable is an {@link ObservableValue}. The created nestings depend
52+
* on this builder's outer observable and nesting steps and adds the specified step as the next one.
53+
*
54+
* @param <N>
55+
* the type wrapped by the created nesting builder
56+
* @param nestingStep
57+
* the function which performs the nesting step from one observable to the next
58+
* @return an {@link ObservableValueNestingBuilder} which builds a nesting from this builder's settings and the
59+
* specified nesting steps
60+
* @throws NullPointerException
61+
* if the specified function is null
62+
*/
63+
public <N> ObservableValueNestingBuilder<N> nestObservable(NestingStep<T, ObservableValue<N>> nestingStep) {
64+
Objects.requireNonNull(nestingStep, "The argument 'nestingStep' must not be null.");
65+
return new ObservableValueNestingBuilder<N>(this, nestingStep);
66+
}
67+
68+
/**
69+
* Returns a builder for nestings whose inner observable is a {@link Property}. The created nestings depend on this
70+
* builder's outer observable and nesting steps and adds the specified step as the next one.
71+
*
72+
* @param <N>
73+
* the type wrapped by the created nesting builder
74+
* @param nestingStep
75+
* the function which performs the nesting step from one observable to the next
76+
* @return an {@link ObservableValueNestingBuilder} which builds a nesting from this builder's settings and the
77+
* specified nesting steps
78+
* @throws NullPointerException
79+
* if the specified function is null
80+
*/
81+
public <N> ObjectPropertyNestingBuilder<N> nestProperty(NestingStep<T, Property<N>> nestingStep) {
82+
Objects.requireNonNull(nestingStep, "The argument 'nestingStep' must not be null.");
83+
return new ObjectPropertyNestingBuilder<N>(this, nestingStep);
84+
}
85+
86+
/**
87+
* Returns a builder for nestings whose inner observable is an {@link IntegerProperty}. The created nestings depend
88+
* on this builder's outer observable and nesting steps and adds the specified step as the next one.
89+
*
90+
* @param nestingStep
91+
* the function which performs the nesting step from one observable to the next
92+
* @return an {@link ObservableValueNestingBuilder} which builds a nesting from this builder's settings and the
93+
* specified nesting steps
94+
* @throws NullPointerException
95+
* if the specified function is null
96+
*/
97+
public IntegerPropertyNestingBuilder nestIntegerProperty(NestingStep<T, IntegerProperty> nestingStep) {
98+
Objects.requireNonNull(nestingStep, "The argument 'nestingStep' must not be null.");
99+
return new IntegerPropertyNestingBuilder(this, nestingStep);
100+
}
101+
102+
//#end NEST
103+
104+
}

0 commit comments

Comments
 (0)