I'm very new to the FHIR standard and I could use some help figuring out how to evaluate a ruleExpression against an object.
Here is my object:
#ResourceDef(name = "TestObj", profile = "http://hl7.org/fhir/StructureDefinition/TestObj")
#Data
public class TestObj extends DomainResource {
private static final long serialVersionUID = 1L;
#Child(name = "numMarbles")
#Extension(url = "http://hl7.org/fhir/CustomExtension/numMarbles", definedLocally = true, isModifier = false)
#Description(shortDefinition = "The number of marbles I have in my pocket")
private IntegerType numMarbles;
}
I'm trying to figure out how to run a rule evaluation on it. For example:
String ruleExp = "%numMarbles > 3"
In order to try options.. I've setup the following integration test:
#Test
void doRuleEval() throws Exception {
TestObj t = new TestObj();
t.setNumMarbles(4);
String ruleExp = "%numMarbles > '3'";
FhirPathR4 path = new FhirPathR4(fhirContext);
// ?????
Object something = path.evaluate(t, ruleExp, null);
// Line above always fails: "unknown fixed constant %numMarbles"
log.info("something: " + something.toString());
}
I've scoured the FHIR documentation and can't find java examples for how to evaluate dynamic rules against FHIR models. In the Javascript library we used the "compile" method but I can't find the equivalent Java method.
I feel like I'm missing something fundamental here.
The "evaluate" method is not documented - it takes in an "IBase" object which is any FHIR object from what I can tell, and returns some sort of list... who knows.
The FhirPathR4 object also contains a "parse" method that returns nothing and is also un-documented.
Thanks for any help or tips to point me in the right direction for evaluating a "ruleExpression" against an object's fields.
I would go onto the HAPI FHIR Google group as ask about the evaluate method there.
https://groups.google.com/g/hapi-fhir?pli=1
Related
I am trying to unit test a Java class with a method containing a lambda function. I am using Groovy and Spock for the test. For proprietary reasons I can't show the original code.
The Java method looks like this:
class ExampleClass {
AsyncHandler asynHandler;
Component componet;
Component getComponent() {
return component;
}
void exampleMethod(String input) {
byte[] data = input.getBytes();
getComponent().doCall(builder ->
builder
.setName(name)
.data(data)
.build()).whenCompleteAsync(asyncHandler);
}
}
Where component#doCall has the following signature:
CompletableFuture<Response> doCall(Consumer<Request> request) {
// do some stuff
}
The groovy test looks like this:
class Spec extends Specification {
def mockComponent = Mock(Component)
#Subject
def sut = new TestableExampleClass(mockComponent)
def 'a test'() {
when:
sut.exampleMethod('teststring')
then:
1 * componentMock.doCall(_ as Consumer<Request>) >> { args ->
assert args[0].args$2.asUtf8String() == 'teststring'
return new CompletableFuture()
}
}
class TestableExampleClass extends ExampleClass {
def component
TestableExampleClass(Component component) {
this.component = component;
}
#Override
getComponent() {
return component
}
}
}
The captured argument, args, shows up as follows in the debug window if I place a breakpoint on the assert line:
args = {Arrays$ArrayList#1234} size = 1
> 0 = {Component$lambda}
> args$1 = {TestableExampleClass}
> args$2 = {bytes[]}
There are two points confusing me:
When I try to cast the captured argument args[0] as either ExampleClass or TestableExampleClass it throws a GroovyCastException. I believe this is because it is expecting Component$Lambda, but I am not sure how to cast this.
Accessing the data property using args[0].args$2, doesn't seem like a clean way to do it. This is likely linked to the casting issue mentioned above. But is there a better way to do this, such as with args[0].data?
Even if direct answers can't be given, a pointer to some documentation or article would be helpful. My search results discussed Groovy closures and Java lambdas comparisons separately, but not about using lambdas in closures.
Why you should not do what you are trying
This invasive kind of testing is a nightmare! Sorry for my strong wording, but I want to make it clear that you should not over-specify tests like this, asserting on private final fields of lambda expressions. Why would it even be important what goes into the lambda? Simply verify the result. In order to do a verification like this, you
need to know internals of how lambdas are implemented in Java,
those implementation details have to stay unchanged across Java versions and
the implementations even have to be the same across JVM types like Oracle Hotspot, OpenJ9 etc.
Otherwise, your tests break quickly. And why would you care how a method internally computes its result? A method should be tested like a black box, only in rare cases should you use interaction testing,where it is absolutely crucial in order to make sure that certain interactions between objects occur in a certain way (e.g. in order to verify a publish-subscribe design pattern).
How you can do it anyway (dont!!!)
Having said all that, just assuming for a minute that it does actually make sense to test like that (which it really does not!), a hint: Instead of accessing the field args$2, you can also access the declared field with index 1. Accessing by name is also possible, of course. anyway, you have to reflect on the lambda's class, get the declared field(s) you are interested in, make them accessible (remember, they are private final) and then assert on their respective contents. You could also filter by field type in order to be less sensitive to their order (not shown here).
Besides, I do not understand why you create a TestableExampleClass instead of using the original.
In this example, I am using explicit types instead of just def in order to make it easier to understand what the code does:
then:
1 * mockComponent.doCall(_ as Consumer<Request>) >> { args ->
Consumer<Request> requestConsumer = args[0]
Field nameField = requestConsumer.class.declaredFields[1]
// Field nameField = requestConsumer.class.getDeclaredField('arg$2')
nameField.accessible = true
byte[] nameBytes = nameField.get(requestConsumer)
assert new String(nameBytes, Charset.forName("UTF-8")) == 'teststring'
return new CompletableFuture()
}
Or, in order to avoid the explicit assert in favour of a Spock-style condition:
def 'a test'() {
given:
String name
when:
sut.exampleMethod('teststring')
then:
1 * mockComponent.doCall(_ as Consumer<Request>) >> { args ->
Consumer<Request> requestConsumer = args[0]
Field nameField = requestConsumer.class.declaredFields[1]
// Field nameField = requestConsumer.class.getDeclaredField('arg$2')
nameField.accessible = true
byte[] nameBytes = nameField.get(requestConsumer)
name = new String(nameBytes, Charset.forName("UTF-8"))
return new CompletableFuture()
}
name == 'teststring'
}
A simple question on SPEL collection selection.
Look at section 10.5.17 Collection Selection on this page
https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html
List<Inventor> list = (List<Inventor>) parser.parseExpression(
"Members.?[Nationality == 'Serbian']").getValue(societyContext);
What i need is the selection 'Serbian' to come from outside and not be a fixed hard coded String.
Just for arguments sake consider that, we could get it as "selectedNationality" from the same society class from the same page in the link.
Modified class with selectedNationality
public class Society {
private String name;
public static String Advisors = "advisors";
public static String President = "president";
private List<Inventor> members = new ArrayList<Inventor>();
private Map officers = new HashMap();
// new selector field
private String selectedNationality;
......
}
New Selection
The new selection SPEL would look like
List<Inventor> list = (List<Inventor>) parser.parseExpression(
"Members.?[Nationality == selectedNationality]").getValue(societyContext);
When we try that the error is that "selectedNationality" is not a part of the Member object.
Does that mean that for collection selection in spring expression language we would need a hard coded String ? If yes does anyone know why ?
Found out how to do it. So the way is to use variables
see 10.5.11 Variables # [https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html][1]
Set Variable
So in our case we wold do this set variable :
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
context.setVariable("selectedNationality ", "Serbian");
New Selection
The new selection SPEL would look like this with #selectedNationality
List<Inventor> list = (List<Inventor>) parser.parseExpression(
"Members.?[Nationality == #selectedNationality]").getValue(societyContext);
Works like a charm !
I'm putting more attention into unit tests these days and I got in a situation for which I'm not sure how to make a good test.
I have a function which creates and returns an object of class X. This X class is part of the framework, so I'm not very familiar with it's implementation and I don't have freedom as in the case of my "regular collaborator classes" (the ones which I have written). Also, when I pass some arguments I cannot check if object X is set to right parameters and I'm not able to pass mock in some cases.
My question is - how to check if this object was properly created, that is, to check which parameters were passed to its constructor? And how to avoid problem when constructor throws an exception when I pass a mock?
Maybe I'm not clear enough, here is a snippet:
public class InputSplitCreator {
Table table;
Scan scan;
RegionLocator regionLocator;
public InputSplitCreator(Table table, Scan scan, RegionLocator regionLocator) {
this.table = table;
this.scan = scan;
this.regionLocator = regionLocator;
}
public InputSplit getInputSplit(String scanStart, String scanStop, Pair<byte[][], byte[][]> startEndKeys, int i) {
String start = Bytes.toString(startEndKeys.getFirst()[i]);
String end = Bytes.toString(startEndKeys.getSecond()[i]);
String startSalt;
if (start.length() == 0)
startSalt = "0";
else
startSalt = start.substring(0, 1);
byte[] startRowKey = Bytes.toBytes(startSalt + "-" + scanStart);
byte[] endRowKey = Bytes.toBytes(startSalt + "-" + scanStop);
TableSplit tableSplit;
try {
HRegionLocation regionLocation = regionLocator.getRegionLocation(startEndKeys.getFirst()[i]);
String hostnamePort = regionLocation.getHostnamePort();
tableSplit = new TableSplit(table.getName(), scan, startRowKey, endRowKey, hostnamePort);
} catch (IOException ex) {
throw new HBaseRetrievalException("Problem while trying to find region location for region " + i, ex);
}
return tableSplit;
}
}
So, this creates an InputSplit. I would like to know whether this split is created with correct parameters. How to do that?
If the class is part of a framework, then you shouldn't test it directly, as the framework has tested it for you. If you still want to test the behaviour of this object, look at the cause-reaction this object would cause. More specifically: mock the object, have it do stuff and check if the affected objects (which you can control) carry out the expected behaviour or are in the correct state.
For more details you should probably update your answer with the framework you're using and the class of said framework you wish to test
This is possibly one of those cases where you shouldn't be testing it directly. This object is supposedly USED for something, yes? If it's not created correctly, some part of your code will break, no?
At some point or another, your application depends on this created object to behave in a certain way, so you can test it implicitly by testing that these procedures that depend on it are working correctly.
This can save you from coupling more abstract use cases from the internal workings and types of the framework.
I have a class like below.
public class Login {
private Keyword browser;
private String page;
}
Keyword is a class in different package. I want to get the fully qualified name of the class Keyword while parsing the Login class using javaparser.
You cannot do that using JavaParser because JavaParser does not resolve symbols. To resolve the name Keyword to a class you need to do several things:
* implements proper scope rules (you need to look for internal classes, then for other classes inside the same file, then to consider imports...)
* it depends on the classpath used to compile: changing it the same class could be resolved differently
To do that a symbol resolver should be written: it is not trivial but doable. If you are interested in the subject you can read a post I just wrote How to build a symbol solver for Java, in Clojure. The post contains also a link to the code, freely available on GitHub.
Source: I am a JavaParser contributor
You can use the JavaParser Symbol Solver:
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-symbol-solver-core</artifactId>
<version>3.14.5</version>
</dependency>
Then parse the code using the following configuration:
CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(),
new JavaParserTypeSolver(sourceRoot));
final ParserConfiguration config = new ParserConfiguration()
.setStoreTokens(true)
.setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver));
SourceRoot root = new SourceRoot(Paths.get("/path/to/project/"));
root.parse("", config, (Path localPath, Path absolutePath, ParseResult<CompilationUnit> result) -> {
// Do something with the CompilationUnit
return Result.DONT_SAVE;
});
We can now get the fully qualified identifier of any ReferenceType using:
ResolvedType type = referenceType.resolve();
String qualifiedName = type.getQualifiedName();
Nobody so far appears to have read the question, but if you're parsing the source code, either it is in the current package or it is imported by an import statement.
I would have expected a Java parser writer or user to know that.
I wrote a method that can get the fully qualified name on basis of a ClassOrInterfaceDeclaration object (latest version of JavaParser):
private static String getFullyQualifiedName(ClassOrInterfaceDeclaration c2) {
String name = "";
ClassOrInterfaceDeclaration parentClass = c2.getParentNode().isPresent() ? getClass(c2.getParentNode().get()): null;
if(parentClass!=null) {
name+=getFullyQualifiedName(parentClass)+".";
} else {
CompilationUnit u = getCompilationUnit(c2);
if(u!=null && u.getPackageDeclaration().isPresent()) {
name+=u.getPackageDeclaration().get().getNameAsString()+".";
}
}
return name+c2.getNameAsString();
}
private static ClassOrInterfaceDeclaration getClass(Node n1) {
while (!(n1 instanceof ClassOrInterfaceDeclaration)) {
if(n1.getParentNode().isPresent()) {
n1 = n1.getParentNode().get();
} else return null;
}
return (ClassOrInterfaceDeclaration)n1;
}
private static CompilationUnit getCompilationUnit(Node n1) {
while (!(n1 instanceof CompilationUnit)) {
if(n1.getParentNode().isPresent()) {
n1 = n1.getParentNode().get();
} else return null;
}
return (CompilationUnit)n1;
}
A much simpler version can be used if you obtain the ClassOrInterfaceType of the class:
private static String getFullyQualifiedName(ClassOrInterfaceType e) {
String name = "";
if(e.getScope().isPresent())
name+=getFullyQualifiedName(e.getScope().get())+".";
return name+e.getNameAsString();
}
I hope this is of help to anyone!
If you are using the visitors, it seems that you only get the start and end indexes inside the source file for having the type name. That will not get you the fully qualified name.
So you should implement the visit(ImportDeclaration, A) method also in your custom visitor. This method then must store the import declarations, so you can later - when the method visit(FieldDeclaration, A) gets called - refer to the imported packages and assemble the fully qualified name.
JavaParser does not resolve imports (this isn't usually considered its job, anyway). You have to manually step through the import statements and search if the Keyword belongs to them. Keep in mind that Java implicitly does a import java.lang.*, otherwise you won't resolve types such as String.
Spring Roo has a JavaParserUtils class containing a method getJavaType(CompilationUnitServices compilationUnitServices, ClassOrInterfaceDeclaration cid). The class is not designed for usage outside of Roo, but you can use as a template for solving your problem.
this might be a better solution for your problem,
using instance of.
use of "Instance of" in java
I have this property in a visual basic class. NET 2008, the property in addition to the get and set has a parameter called "pParam. "
Public Property UpdateField(ByVal pParam As String) As String
Get
Return Me.idField
End Get
Set(ByVal value As String)
Me.idField = value
If pParam = "NEW" Then
// some code here
End If
End Set
End Property
which is the equivalent of this in java code?
to use I do the following:
oClass.UpdateField("NEW") = 1850
I have this code in java
public void setUpdateField(String idField) {
this.idField = idField;
}
public String getUpdateField() {
return idField;
}
but I need to put the parameter "pParam"
Thanks in advance.
What you've got in the .NET code is an indexer in C# terms. There's no equivalent in Java - you'll just need to take two parameters:
public void setUpdateField(String idField, String pParam) {
...
}
Frankly I think it's a little odd that the "getter" in .NET doesn't seem to use the index...