Skip to content

Instantly share code, notes, and snippets.

@gunnarmorling
Created March 8, 2012 17:09
Show Gist options
  • Save gunnarmorling/2002111 to your computer and use it in GitHub Desktop.
Save gunnarmorling/2002111 to your computer and use it in GitHub Desktop.
Options for property pathes for method validation
public class Book {
@NotNull
private String title;
}
public class Library {
public void addBook(@NotNull @Valid Book book) { ... }
public void addAllBooks(@NotNull @Valid List<Book> books) { ... }
@NotNull
public String getLocation() { ... }
}
//Option #A1 (currently in draft): Have a single node representing a parameter or return value *and* the hosting method/constructor
//path to @NotNull on the "book" parameter of addBook()
Node(name=book, methodDescriptor=..., parameterDescriptor=..., constructorDescriptor=null)
//path to @NotNull on the "title" attribute of the book passed as argument to addBook()
Node(name=book, methodDescriptor=..., parameterDescriptor=..., constructorDescriptor=null)
Node(name=title, methodDescriptor=null, parameterDescriptor=null, constructorDescriptor=null)
//path to @NotNull on the "title" attribute of the 4th book in the list passed as argument to addAllBooks()
Node(name=books, methodDescriptor=..., parameterDescriptor=..., constructorDescriptor=null)
Node(name=title, methodDescriptor=null, parameterDescriptor=null, constructorDescriptor=null, inIterable=true, index=3)
//path to @NotNull on the return value of getLocation()
Node(name=???, methodDescriptor=..., parameterDescriptor=null, constructorDescriptor=null)
//Option #A2: Have individual node instances for the hosting method/constructor and parameter/return value
//path to @NotNull on the "book" parameter of addBook()
Node(name=addBook, methodDescriptor=..., parameterDescriptor=null, constructorDescriptor=null)
Node(name=book, methodDescriptor=null, parameterDescriptor=..., constructorDescriptor=null)
//path to @NotNull on the "title" attribute of the book passed as argument to addBook()
Node(name=addBook, methodDescriptor=..., parameterDescriptor=null, constructorDescriptor=null)
Node(name=book, methodDescriptor=null, parameterDescriptor=..., constructorDescriptor=null)
Node(name=title, methodDescriptor=null, parameterDescriptor=null, constructorDescriptor=null)
//path to @NotNull on the "title" attribute of the 4th book in the list passed as argument to addAllBooks()
Node(name=addAllBooks, methodDescriptor=..., parameterDescriptor=null, constructorDescriptor=null)
Node(name=books, methodDescriptor=null, parameterDescriptor=..., constructorDescriptor=null)
Node(name=title, methodDescriptor=null, parameterDescriptor=null, constructorDescriptor=null, inIterable=true, index=3)
//path to @NotNull on the return value of getLocation()
Node(name=getLocation, methodDescriptor=..., parameterDescriptor=null, constructorDescriptor=null)
Node(name=???, methodDescriptor=null, parameterDescriptor=null, constructorDescriptor=null)
//Option #B1 (currently in proposal): Have one single node type with all required attributes
interface Node {
String getName();
boolean isInIterable();
Integer getIndex();
Object getKey();
MethodDescriptor getMethodDescriptor();
ConstructorDescriptor getConstructorDescriptor();
ParameterDescriptor getParameterDescriptor();
//currently not in the proposal, but it seems actually more regular to me
//than representing return value constraints on the method descriptor
ReturnValueDescriptor getReturnValueDescriptor();
}
//Iterating over a Path
Path path = ...;
Iterator<Node> nodeIterator = path.iterator();
while(nodeIterator.hasNext()) {
Node node = nodeIterator.next();
if(node.getMethodDescriptor() != null) {
//...
}
else if(node.getConstructorDescriptor() != null) {
//...
}
}
Option #B2: Have a separate sub type for each "kind" of node. This requires option #A2, as we otherwise would need "combined" element kinds such as METHOD_PARAMETER, CONSTRUCTOR_PARAMETER etc. which doesn't seem nice
enum NodeKind {
BEAN, PROPERTY, METHOD, CONSTRUCTOR, PARAMETER, RETURN_VALUE;
}
interface Node {
String getName();
boolean isInIterable();
Integer getIndex();
Object getKey();
NodeKind getKind();
//should we offer something like this?
PropertyNode asPropertyNode();
MethodNode asMethodNode();
...
}
public interface MethodNode extends Node {
MethodDescriptor getMethodDescriptor();
}
//Iterating over a Path
Path path = ...;
Iterator<Node> nodeIterator = path.iterator();
while(nodeIterator.hasNext()) {
Node node = nodeIterator.next();
if(node.getKind() == Kind.METHOD) {
MethodDescriptor = ((MethodNode)node).getMethodDescriptor();
...
}
else if(node.getKind() == Kind.PARAMETER) {
ParameterDescriptor = ((ParameterNode)node).getParameterDescriptor();
...
}
...
}
//Option #B3: Have one single node type with a reference to ElementDescriptor, have getKind() on ElementDescriptor
interface Node {
String getName();
boolean isInIterable();
Integer getIndex();
Object getKey();
ElementDescriptor getElementDescriptor();
}
//Iterating over a Path
Path path = ...;
Iterator<Node> nodeIterator = path.iterator();
while(nodeIterator.hasNext()) {
Node node = nodeIterator.next();
if(node.getElementDescriptor().getKind() == ElementKind.METHOD) {
MethodDescriptor = (MethodDescriptor)node.getElementDescriptor();
//...
}
if(node.getElementDescriptor().getKind() == ElementKind.PARAMETER) {
ParameterDescriptor = (ParameterDescriptor)node.getElementDescriptor();
//...
}
}
@gunnarmorling
Copy link
Author

I think there are three (orthogonal) main questions right now with respect to property pathes for method level constraints:

  • A: How many node instances should there be for method level constraints in pathes (options are #A1, and #A2)?
  • B: Should there be one generic node type or several dedicated sub types (options are #B1, #B2, #B3)?
  • C: Should there be a dedicated element descriptor type for return values (oposed to using MethodDescriptor for this)?

In the proposal we currently have options #A1 and #B1. For C my answer would now be yes (we don't have this in the proposal right now). Personally I think we could go with the A1/B1 approach into the draft. It provides all required information and we could still change this to something else (e.g. A2/B3) later on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment