MicroEJ Classpath
MicroEJ Applications run on a target device and their footprint is optimized to fulfill embedded constraints. The final execution context is an embedded device that may not even have a file system. Files required by the application at runtime are not directly copied to the target device, they are compiled to produce the application binary code which will be executed by the Core Engine.
As a part of the compile-time trimming process, all types not required by the embedded application are eliminated from the final binary.
MicroEJ Classpath is a developer defined list of all places containing files to be embedded in the final application binary. MicroEJ Classpath is made up of an ordered list of paths. A path is either a folder or a zip file, called a JAR file (JAR stands for Java ARchive).
Application Classpath explains how the MicroEJ Classpath is built from a MicroEJ Application project.
Classpath Load Model explains how the application contents is loaded from MicroEJ Classpath.
Classpath Elements specifies the different elements that can be declared in MicroEJ Classpath to describe the application contents.
Application Classpath
The MicroEJ Classpath of an Application is built from its Gradle project, in this order:
the classes and resources of the project,
the dependencies of the project, a module before the modules it depends on.
The order of the dependencies comes from Gradle, not from the order of the dependencies block.
Gradle orders the dependencies topologically (i.e. a module comes before the modules it depends on).
For example, the Application below depends on lib-a and lib-b, and lib-a depends on lib-b.
The dependencies block declares lib-b first:
dependencies {
implementation("com.mycompany:lib-b:1.0.0")
implementation("com.mycompany:lib-a:1.0.0")
}
The MicroEJ Classpath puts lib-a before lib-b, because lib-a depends on lib-b:
![digraph classpath {
rankdir=LR
node [shape=box]
subgraph cluster_graph {
label="Dependency graph"
app [label="Application"]
a [label="lib-a"]
b [label="lib-b"]
app -> a
app -> b
a -> b
}
subgraph cluster_order {
label="MicroEJ Classpath (left to right)"
order [shape=record, label="{Application classes and resources|lib-a|lib-b}"]
}
b -> order [style=invis]
}](../_images/graphviz-54f80f38c16cfa411a3e2d708966ab7a6a43cd62.png)
As a result, a system property or constant value declared by the Application overrides the value of the same system property or constant declared by a library, and a system property or constant value declared by a library overrides the one declared by its own dependencies. This applies to System Properties and Constants.
Classpath Load Model
A MicroEJ Application classpath is created via the loading of :
an entry point type,
all
*.[extension].listfiles declared in a MicroEJ Classpath.
The different elements that constitute an application are described in Classpath Elements. They are searched within MicroEJ Classpath from left to right (the first file found is loaded). Types referenced by previously loaded MicroEJ Classpath elements are loaded transitively.
Classpath Load Principle
Classpath Elements
The MicroEJ Classpath contains the following elements:
An entrypoint described in section Application Entry Points;
Types in
.classfiles, described in section Types;Immutables Object data files, described in Section Immutable Objects;
Raw Resources, Images, Fonts and Native Language Support (NLS) described in Application Resources;
*.[extension].listfiles, declaring contents to load. Supported list file extensions and format is specific to declared application contents and is described in the appropriate section.
At source level, Java types are stored in src/main/java folder of the module project,
any other kind of resources and list files are stored in the src/main/resources folder.
Application Entry Points
MicroEJ Application entry point declaration differs depending on the application kind:
In case of a Standalone Application, it is a class that contains a
public static void main(String[])method, declared using the optionapplication.main.class.In case of a Sandboxed Application, it is a class that implements ej.kf.FeatureEntryPoint, declared using the
entryPointproperty in the.kffile in thesrc/main/resources/folder.
Types
MicroEJ types (classes, interfaces) are compiled from source code
(.java) to classfiles (.class). When a type is loaded, all types
dependencies found in the classfile are loaded (transitively).
A type can be declared as a Required type in order to enable the following usages:
to be dynamically loaded from its name (with a call to Class.forName(String));
to retrieve its fully qualified name (with a call to Class.getName()).
when Tiny-Sandbox capability is enabled, to retrieve its package (with a call to Class.getPackage()).
A type that is not declared as a Required type may not have its fully qualified name (FQN) embedded. Its FQN can be retrieved using the stack trace reader tool (see Stack Trace Reader).
Required Types are declared in MicroEJ Classpath using *.types.list
files. The file format is a standard Java properties file, each line
listing either the fully qualified name of a type or, for a primitive
array type, its JVM array descriptor (for example [B for byte[],
[[Z for boolean[][]). Example:
# The following types are marked as MicroEJ Required Types
com.mycompany.MyImplementation
com.mycompany.MyImplementation$MyInnerClass
java.util.Vector
[B
[[Z
Note
Types that are defined from inner classes should be declared with the outer class fully qualified name followed by $ and the name of the inner class.
Note
Primitive array type declaration in *.types.list files require Architecture version 9.0.0 or higher.
With an older Architecture:
SOAR ignores the primitive array types listed in a
*.types.listfile, without any error or warning.When the Embed all type names option is set to
false, Class.forName(String) throws aClassNotFoundExceptionfor every primitive array type.When the Embed all type names option is set to
true, SOAR embeds the names of all types, including the primitive array types that the Application code or its libraries use. Class.forName(String) throws aClassNotFoundExceptionfor a primitive array type that no code uses.
The Simulator finds the primitive array types with Class.forName(String), whatever the content of the
*.types.listfiles.
Resources
Resources are binary files that need to be embedded by the application.
Note
For more details on all supported resources types, please refer to Application Resources chapter.
Raw resources are resources that can be dynamically retrieved with a call to
java.lang.Class.getResourceAsStream(String).
Raw Resources are declared in *.resources.list files (and in *.externresources.list for external resources, see Application Resources).
![digraph D {
internalRaw [shape=diamond, label="internal?"]
rawList [shape=box, label="*.resources.list"]
rawExt [shape=box, label="*.resources.list +\l*.externresources.list"]
subgraph cluster_Raw {
label ="Raw Resource"
internalRaw -> rawList [label="yes"]
internalRaw -> rawExt [label="no=external"]
}
}](../_images/graphviz-c47847d0d8d3fe6990d75c678f74a6fdddb4e842.png)
The file format is a standard Java properties file, each line is a relative /
separated name of a file in MicroEJ Classpath to be embedded as a
resource. Example:
# The following resource is embedded as a raw resource
com/mycompany/MyResource.txt
A resource is 4-bytes aligned in memory by default. Starting from Architecture 8.0.0, it is possible to modify the alignment constraint. Example:
# The following resource is linked to a 32-bytes aligned address in memory.
com/mycompany/MyResource.txt:32
Note
If a Resource is declared multiple times in the classpath, the alignment constraint with the highest value is used. If the alignment constraints are specific to the target, it is recommended to only declare them in the Application project instead of libraries.
If a resource filename contains a delimiter (such as a whitespace, :, or =), the delimiter must be escaped using the backslash \ character in the *.resources.list file.
Example:
# The resource filename: "resource name contains whitespace.txt"
com/mycompany/resource\ name\ contains\ whitespace.txt
Immutable Objects
Immutables objects are regular read-only objects that can be retrieved
with a call to ej.bon.Immutables.get(String). Immutables objects are
declared in files called immutable objects data files, which format is
described in the [BON] specification.
Immutables objects data files are declared in MicroEJ Classpath using
*.immutables.list files. The file format is a standard Java properties file, each line is a / separated name of a relative file
in MicroEJ Classpath to be loaded as an Immutable objects data file.
Example:
# The following file is loaded as an Immutable objects data files
com/mycompany/MyImmutables.data
System Properties
System Properties are key/value string pairs that can be accessed with a call to System.getProperty(String).
System Properties are defined when building a Standalone Application,
by declaring *.properties.list files in MicroEJ Classpath.
The file format is a standard Java properties file. Example:
# The following property is embedded as a System property
com.mycompany.key=com.mycompany.value
microedition.encoding=ISO-8859-1
System Properties are resolved at runtime, and all declared keys and values are embedded as intern Strings.
System Properties can also be defined using Standalone Application Options. This can be done by setting the option with a specific prefix in their name:
Properties for both the Core Engine and the Simulator : name starts with
microej.java.property.*Properties for the Simulator only: name starts with
sim.java.property.*Properties for the Core Engine only: name starts with
emb.java.property.*
For example, to define the property myProp with the value
theValue, set the following option :
microej.java.property.myProp=theValue
Note
A System Property defined as an Application Option takes precedence over a System Property defined in the classpath.
Note
When a key is declared in several *.properties.list files, the value declared in the first file of the classpath is used.
See Classpath Order.
Note
When building a Sandboxed Application, *.properties.list files found in MicroEJ Classpath are silently skipped.
Constants
Constants are key/value string pairs that can be accessed with a
call to ej.bon.Constants.get[Type](String), where Type if one of:
Boolean,
Byte,
Char,
Class,
Double,
Float,
Int,
Long,
Short,
String.
Constants are declared in MicroEJ Classpath *.constants.list files. The file format is a
standard Java properties file. Example:
# The following property is embedded as a constant
myconstantkey=myconstantvalue
Starting from Architecture 8.3.0, it is also possible to define a constant using the following Application Option:
microej.constant.myconstantkey=myconstantvalue
Note
A Constant defined as an Application Option takes precedence over a constant defined in the classpath.
Note
When a key is declared in several *.constants.list files, the value declared in the first file of the classpath is used.
See Classpath Order.
Constants are resolved at binary level without having to recompile the sources.
At link time, constants are directly inlined at the place of
Constants.get[Type] method calls with no cost.
The String key parameter must be resolved as an inlined String:
either a String literal
"myconstantkey"or a
static final Stringfield resolved as a String constant
The String value is converted to the desired type using conversion rules described by the [BON] API.
A boolean constant declared in an if statement condition can be used to fully remove portions of code.
This feature is similar to C pre-processors #ifdef directive with the difference that this optimization is performed at binary level
without having to recompile the sources.
if code removal using a BON boolean constantif (Constants.getBoolean("myconstantkey")) {
System.out.println("this code and the constant string will be fully removed when the constant is resolved to 'false'")
}
Please mind that Constants.getXXX must be inlined in the if condition to take effect.
The following piece of code will not remove the code:
static final boolean MY_CONSTANT = Constants.getBoolean("myconstantkey");
...
if(MY_CONSTANT){
System.out.println("this code will not be removed when MY_CONSTANT is resolved to 'false'")
}
Note
In Multi-Sandbox environment, constants are processed locally within each context. In particular, constants defined in the Kernel are not propagated to Sandboxed Applications.
