The code for this article in on GitHub: jar_mps

Jetbrains MPS is a wonderful tool to create DSLs. We love it and use it regularly in our consultancy work. So we have written about Jetbrains MPS before.

Being a projectional editor allows you to easily create DSLs that can be used through a graphical interface or things like mathematical formulas. Though all this power requires a bit of preparatory work.

One of the most important characteristics of MPS is the fact that it permits to reuse Java code. New Java code can be written in MPS through what it is called the BaseLanguage. However, sometimes we want just to reuse existing Java code inside MPS.

In this tutorial, we are going to see:

  1. How you can load JARs into MPS
  2. How we use this feature to solve a common problem: loading static resources with Java to use them in Jetbrains MPS code.

First we will see how to create a new JAR containing resources and then how to to load an existing JAR in Jetbrains MPS.

Creating a JAR Containing Static Resources

We are going to use a script gradle to create the JAR, because it is more convenient and can be easily automated, but obviously you can do it the way you prefer.

The structure of the project is a traditional Java one, with a resources and a src directories.

Resources project

The gradle project is simple, all we need to do is to create the build.gradle file with the following content.

apply plugin: 'java'

sourceSets.main.resources.srcDirs = [ "resources/" ]
sourceSets.main.resources.includes = [ "**/*.png", "**/*.gif" ]

All we did is indicating where to find the resources and which files to include, in our case image files for icons.

The Java class is equally trivial, we make the icons accessible as static fields.

package com.strumenta.examples.icons;

import javax.swing.*;

public class ExamplesIcons {
    
    public static final ImageIcon MAIN;
    public static final ImageIcon CIRCLE;    

    static {
        MAIN = createImageIcon("/com/strumenta/examples/icons/main.png", "Main Icon");
        CIRCLE = createImageIcon("/com/strumenta/examples/icons/circle.png", "Circle Icon");
    }

    private static ImageIcon createImageIcon(String path, String description) {
        java.net.URL imgURL = ExamplesIcons.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
        } else {
            System.err.println("Icon not loaded: " + path);
            return null;
        }
    }
}

Since we are building icons, we need to import the proper Javax Swing dependency.

Now, we enter the main directory of the gradle project and we build it.

# Linux/Mac OS/Cygwin
./gradlew jar
# Windows
./gradlew.bat jar

The end result should be a resources_project.jar under the build/libs/ directory.

The MPS Project

Now that we have our JAR with the icons, we must make it accessible to MPS code. You can use the same procedure with any existing JAR code that you have.

We prefer to import static resource in their own solution, because it makes the project cleaner. So, we start by creating a solution called com.strumenta.examples.external, which generates a directory with that name and .msd file the same name. Inside the directory there will also be a models directory. Inside the com.strumenta.examples.external directory we manually add a libs directory, with our resources_project.jar.

MPS Solution with the libs directory

We still have to add the generated library to the module, by going to Module Properties (Alt + Enter):

  1. in the Dependencies tab, we add the JDK module and then select Export
    MPS dependencies
  2. in the Java tab, Libraries section, we add the JAR file. In MPS you will see the complete path but internally MPS is saving a relative path, because we inserted the JAR in the solution directory. This is very important because it means that other contributors working on the project on other machines will get the right result even if they put the project in a different path
    MPS Java libraries
  3. in the Common tab, we click Add Model Root->java_classes, then we select the JAR file in the right panel and click Sources to add its content to the models
    MPS Java classes

If your libraries need third-party Java code you should perform steps 2 and 3 for your dependencies. In our case we do use third-party code (Javax Swing), but it is part of the JDK platform already included. So, we do not need to do anything else.

MPS external solution

In a real-world scenario the issue is that there might be a lot of dependencies, especially for complex projects. So, you might want first to collect all the dependencies using a standard tool, like gradle or maven, and then insert them in MPS.
If you now open the ExampleIcons file, you should see something similar to the following image.

If you see some errors in ExamplesIcons you probably added things in the wrong order. You have to add the JDK module first, so that MPS can automatically add what is needed. To confirm that everything is working okay, you can also look at the Model Properties of the icons@java_stub model, it should have automatically included both Java and Javax.Swing among its dependencies (you cannot add them manually).

MPS dependencies model
MPS console

To test the inclusion, you can use the MPS Console. Use CTRL+M to include the external solution and then try the command printText with the instruction ExamplesIcons.MAIN.getDescription(), as in the following image. Then press the Execute button: tt should print “Main Icon”

And that is basically it, you just have to remember to include the module com.strumenta.examples.external as a dependency in each module you use the code included in the JAR. If you want to use the resources in a plugin or a simulator you may want to add it as a runtime dependency.

Include the JAR in build models

If you generate plugins or custom versions of MPS you are going to use build models. In that case you should add your JAR in those build models.
For instance, if you generate a plugin you have to copy the JAR into the directory of the plugin, as in the following image.

MPS plugin

If you forgot to do that you will receive an error when you will try to generate the model related to the build of the plugin.

MPS Error