Skip to content

Commit

Permalink
BVAL-508 Add new proposal on Extractor alternative
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanuelbernard committed Feb 5, 2016
1 parent 0ba852b commit c0618a4
Showing 1 changed file with 75 additions and 32 deletions.
107 changes: 75 additions & 32 deletions proposals/BVAL-508.md
Expand Up @@ -130,58 +130,101 @@ TODO: refine the `Path` approach. One specific question is around indexing of Li
##### Alternative approach: extractors returning `ValueAndPath`

Gunnar proposes an alternative to the extractor.
This approach does not solve the link between constraints location and the targeted extractor.
TODO: evolve it to do it :)
This alternative provides:

class ValueAndPathNode<O> {
Node getPathNode();
O getValue();
}
* one extractor per container type (and not container + value type)
* the extractor selected is the one matching the most specific super type of the container
* only one extractor is executed per container

interface SingleValueExtractor<I, 0> {
ValueAndPathNode<O> extractValue(I input);
}
interface SingleValueExtractor<I, O> {

interface MultiValueExtractor<I, 0> {
Iterator<ValueAndPathNode<O>> extractValues(I input);
O extractValue(I input);

// only invoked if invalid; Property name enough as input?
// do we even need any input?
Path.Node getNode(String property);
}

// default impls
interface MultiValueExtractor<I, O> {

class MapExtractor implements MultiValueExtractor<Map, Object> {
extractValue() {
return map key and value alternating; with the right node and value
}
}
ValueAndNodeIterator<O> extractValues(I input);

class ObjectRefExtractor implements SingleValueExtractor<Object, Object> {
extractValue(Object v) {
return v;
}
}
// should it extend Java Iterator?
public interface ValueAndNodeIterator<O> {

boolean hasNext();

O next();

// Used to identify the location where constraints should be looked for
TypeVariable<?> typeVariable();

class OptionalRefExtractor implements SingleValueExtractor<Optional, Object> {
extractValue(Optional v) {
return v.get();
// only invoked if invalid; Property name enough as input?
// might need to be Path instead of Path.Node
Path.Node getNode(String property);
}
}

// user-custom extractors
// implementation example
class MapExtractor implements MultiValueExtractor<Map, Object> {

class ThreeTupleExtractor implements MultiValueExtractor<ThreeTuple, Object> {
extractValue() {
return iterator with the three elements
public ValueAndNodeIterator<Object> extractValues(Map input) {
Set<Map.Entry<?, ?>> entrySet = input.entrySet();
final Iterator<Map.Entry> iterator = input.entrySet().iterator();
final TypeVariable<Class<Map>> k = Map.class.getTypeParameters()[0];
final TypeVariable<Class<Map>> v = Map.class.getTypeParameters()[1];

// returns alternatively key and value for each map entry
return new ValueAndNodeIterator<Object>() {

private boolean atKey = true;
private Map.Entry<?, ?> current;

public boolean hasNext() {
return iterator.hasNext();
}

public Object next() {
if ( atKey ) {
current = iterator.next();
atKey = false;
return current.getKey();
}
else {
atKey = true;
return current.getValue();
}
}

public TypeVariable<?> typeVariable() {
return atKey ? k : v;
}

public Node getNode(String property) {
// TODO Auto-generated method stub
return null;
}
};
}
}


In this approach, a container offering multiple value types (like `Map`) will have a unique extractor.
This extractor will return (an iterator of) `Path.Node` + value.
This extractor will return (an iterator of) the values and offer the ability to compute the `Path.Node`
and retrieve the `TypeVariable`.
For example the map extractor will return `2n` elements (for a map of `n`).

The `TypeVariable` is used to know which type parameter this value corresponds to.
Constraints will be looked on this type parameter - whether on the class itself or its subclasses.

Open questions and limitations:

* each navigation imposes the creation of a `ValueAndPathNode` object + the `Path.Node` object (or even `Path` object graph). That's a lot of unnecessary object creation in the validation critical path.
* the link between a constraint location (which type use location) to which `Path` is undefined: so we don't know which constraint to apply.
* is `TypeVariable` both enough and necessary to express the type parameter targeted?
* an alternative is to provide an object containing the same info as `@ExtractedValue`: parameter host and parameter index
* At first sight, `TypeVariable` does not provide the parameter host information
* this model makes extractor resolution simpler as a single extractor is present per container
* but it does not allow extractor composition
* a subclass of Collection with special extracting demands will need to reimplement the regular collection extraction logic as well as its custom one in one class

### Constraints applied and containers

Expand Down

0 comments on commit c0618a4

Please sign in to comment.