@Retention(value=SOURCE) @Target(value=METHOD) public @interface ComputedProperty
Model
annotation to
define a derived property. Value of derived property is based on values
of regular properties
as specified by Model.properties()
.
The name of the computed/derived property is the name of the annotated method.
Classic Example
Imagine one wants to represent a formula with two variables and certain
computations performed on top of them. One can represent such computations
with @ComputedProperty
:
@There are two variablesModel
(className = "Formula", properties = { @Property
(name = "a", type = int.class), @Property
(name = "b", type = int.class), }) public class SquaresTest { @ComputedProperty
static int plus(Formula model) { return model.getA() + model.getB(); } @ComputedProperty
static int minus(Formula model) { return model.getA() - model.getB(); } @ComputedProperty
static int aPlusBTimesAMinusB(Formula both) { return both.getPlus() * both.getMinus(); } }
a
and b
with appropriate getters and
setters. In addition there are derived properties plus
, minus
and aPlusBTimesAMinusB
which is based on the previous two derived
properties. The usage then follows classical bean patterns:
final Formula formula = new Formula(3, 2); assertEquals(formula.getAPlusBTimesAMinusB(), 5);
final Formula formula = new Formula(5, 2); assertEquals(formula.getAPlusBTimesAMinusB(), 21);
Shorthand Syntax
Sometimes using the getters to compute a property may lead to unnecessary verbosity. As such there is a shorthand syntax for defining the derived properties. Rather than writing:
static int aSquareMinusBSquareClassic(Formula squares) { return squares.getA() * squares.getA() - squares.getB() * squares.getB(); }
one can choose decomposition - pattern matching and name the properties one wants to access in the signature of the method:
@ComputedProperty
static int aSquareMinusBSquare(int a, int b) {
return a * a - b * b;
}
The arguments
of the method must match names and types of some of the properties
from Model.properties()
list.
As soon as one of the properties the derived property method is accessing changes, the method is called again to recompute its new value and the change is notified to the underlying (rendering) technology.
Method's return type defines the type of the derived property. It may be
any primitive type, String
, enum type
or a
type generated by @Model
annotation. One may
also return a list of such (boxed) type
(for example List
<String
> or List
<Integer
>).
An example testing
whether a number is a prime using a ComputedProperty
is available
on-line.
public abstract String write
By default the computed properties are read-only (e.g. they only have a getter), however one can make them mutable by defining a static method that takes two parameters:
Object
) of that type
Power of a Value Example
Imagine you want to compute power of a number. You can define simple
model class and a computed property pow
inside it:
@Model
(className = "Power", properties = { @Property
(name = "value", type = double.class) }) public class PowerTest { @ComputedProperty
static double pow(double value) { return value * value; } }
Such code allows you to find out that the power of three is nine:
Power p = new Power(3); assertEquals(p.getPow(), 9, 0.01);
However you can change the above example to also compute a square of the
value by making the power
property writable:
@ComputedProperty
(write = "sqrt") static double power(double value) { return value * value; } static void sqrt(Power model, double value) { model.setValue(Math
.sqrt(value)); }
Then it is possible to use the same model to find out that square of four is two:
Power p = new Power(); p.setPower(4.0); assertEquals(2.0, p.getValue(), 0.01, "Adjusted to square of four"); assertEquals(4.0, p.getPower(), 0.01, "Was set to four"); assertEquals(4.0, p.getPow(), 0.01, "Kept in sync with power property");
Implementation note:
There cannot be two properties of the same name and different
behavior and as such the example is using two properties pow
and power
. One of them is read-only and the second is writable.
The body of both methods is the same however.
Copyright © 2021 The Apache Software Foundation. All rights reserved.