On the last page we looked at calling native java code from a DSL. On this page we look at calling the DSL from the java code and other interactions between a DSL and native java code, such as:
- Calling code within the current DSL file.
- Calling code between two different DSL files (possibly in the same package).
- Calling java library code such as 'String' from a DSL.
- Calling (user written) java code from a DSL.
- Calling a DSL from java code.
- Circular references between a DSL and user written java code.
- Inheriting from a native java class or interface in a DSL.
- Inheriting from a DSL in a native java class.
Linking within the current DSL file.
As an example lets take the example from the xtext documentation. I chose this example because it has internal (non-containment) links such as:
|
grammar org.example.domainmodel.Domainmodel with org.eclipse.xtext.common.Terminals generate domainmodel "http://www.example.org/domainmodel/Domainmodel" Domainmodel : elements += Type* ; Type: DataType | Entity ; DataType: 'datatype' name = ID ; Entity: 'entity' name = ID ('extends' superType = [Entity])? '{' features += Feature* '}' ; Feature: many?='many'? name = ID ':' type = [Type] ; |
This generates the ECore model on the right: We can see that the two links mentioned are shown as arrows (without a dimond at the start of the arrow). These represent EReferences in the model. |
The destination of these EReferences is represented by a name (see naming page).
The source end uses the name (String) to link to the destination.
The runtime code calls getScope(EObject,EReference) (see scoping page) To resolve the connection.
For a complete explanation of how the links are resolved using scoping see example1 on the scoping page.
Calling a DSL from Java Code.
Here is some simple code for my DSL. | // my DSL code package example2 import java.lang.String class HelloWorld2 { def String getString(String s) { (new String("hello ")).concat(s) } } |
It is called by this native java code | // user written java code package example2; class myJavaCode { public static void main(String[] args) { HelloWorld2 hw =new HelloWorld2(); System.out.println(hw.getString("me")); } } |
This works fine, provided that we add 'src-gen' to the java build path:
Note 1. I would have liked to replaces the line: (new String("hello ")).concat(s)
with the line: return "hello "+s
but it gave the error:
Couldn't resolve reference to JvmIdentifiableElement '+'.
DSL and User Written Java Code with Circular References
Here the java code depends on (calls) the DSL and the DSL code depends on the java code, like this:
Here is some simple code for my DSL. | // my DSL code package example3 import example3 import java.lang.String class HelloWorld3 { def String getString(String s) { return getString2(s) } } |
It is called by this native java code | // user written java code package example3; class myJavaCode { public static void main(String[] args) { HelloWorld3 hw =new HelloWorld3(); System.out.println(hw.getString("me")); } public String getString2(String s) { return "hello"+s; } } |
There is a problem here since the DSL won't generate any java when it has errors and it will have errors because the java code can't link to it. How can we break this loop? One way would be to comment out the link to the java code to allow some java to be generated form the DSL, then remove the comment so that the java code is then correct. However this is messy and not what we would expect users to have to do.
Further Reading
Other related pages:
This itemis blog has more information about this topic.