The "MIM serialization API for Java" is a library for JVM based languages (Java, Kotlin, Scala, Groovy, Clojure etc.) for reading (and navigating) and writing MIM (Metamodel voor Informatiemodellering) XML serializations following MIM versions 1.1.0, 1.1.1 and 1.2. The library makes use of the JAXB framework to map Java classes to XML and vice versa based on the MIM XML Schemas. A number of the generated classes is extended to provide important extra functionality.
- Overview
- Adding the API to your build
- Loading an existing MIM serialization
- Creating a new MIM model
- Saving a MIM model
- Javadocs
- Example project
The API's Maven group ID is nl.armatiek.mim
, and its artifact ID is mim-serialization-api
.
To add a dependency on the API using Maven, use the following:
<dependency>
<groupId>nl.armatiek.mim</groupId>
<artifactId>mim-serialization-api</artifactId>
<version>0.9.1</version>
</dependency>
To add a dependency using Gradle:
dependencies {
implementation("nl.armatiek.mim:mim-serialization-api:0.9.1")
}
An existing MIM serialization (like the ones that are generated by Imvertor) can be loaded (or "unmarshalled", "deserialized") using the static methods loadModel
of the class MimSerializationApi
:
public static MimModel loadModel(InputStream mimSerialization) throws MimSerializationApiLoadException;
or:
public static MimModel loadModel(Path mimSerializationPath) throws MimSerializationApiLoadException;
The MimModel that is returned is of one of the classes:
nl.geostandaarden.mim_1_2.relatiesoort.MimModel
nl.geostandaarden.mim_1_2.relatierol.MimModel
nl.geostandaarden.mim_1_1_1.relatiesoort.MimModel
nl.geostandaarden.mim_1_1_1.relatierol.MimModel
nl.geostandaarden.mim_1_1_0.relatiesoort.MimModel
nl.geostandaarden.mim_1_1_0.relatierol.MimModel
depending on the MIM versie
and the relatiemodelleringstype
("Relatiesoort leidend" or "Relatierol leidend") that the API detected in the MIM serialization.
The API can also validate the MIM serialization against the MIM XML schema during load:
public static MimModel loadModel(InputStream mimSerialization, ValidationEventHandler eventHandler) throws MimSerializationApiLoadException;
or:
public static MimModel loadModel(Path mimSerializationPath, ValidationEventHandler eventHandler) throws MimSerializationApiLoadException;
for instance:
MimModel mimModel = MimSerializationApi.loadModel(mimSerialization, new ValidationEventHandler() {
@Override
public boolean handleEvent(ValidationEvent event) {
System.out.println("Validation error: " + event.getMessage() + " (" + event.getSeverity() + ")");
return event.getSeverity() == ValidationEvent.WARNING;
}
});
The return value of the handleEvent
method indicates that the loading should only continue if the severity of the parse error is WARNING.
Traversal of the MIM model starts with obtaining the Informatiemodel object:
Informatiemodel informatiemodel = mimModel.getInformatiemodel();
For instance getting all Objecttypes of the first Domein:
List<Objecttype> objectTypes = mimModel.getInformatiemodel().getPackages().getDomein().get(0).getObjecttypen().getObjecttype();
A number of the classes that were generated by JAXB are extended to provide important extra functionality. These classes have a name ending on "Ex", like ObjecttypeEx
, AttribuutsoortEx
, RefTypeEx
or
XhtmlTextEx
. During traversal of the information model an object of for instance the class Objectype
, Attribuutsoort
, RefType
or XhtmlText
can always be cast to ObjecttypeEx
, AttribuutsoortEx
,
RefTypeEx
and XhtmlTextEx
to access this extra functionality.
A typical MIM serialization contains a lot of internal links, like links from an Attribuutsoort to a Datatype (like a Primitief datatype, Gestructureerd datatype, Enumeratie, Referentielijst or a Codelijst), links from an Objecttype to its supertype and so on. In the MIM serialisation these links are coded according to the XLink standard, for instance:
<mim:PrimitiefDatatype id="fietsenwinkel-contacten-iban">
...
<mim:naam>IBAN</mim:naam>
...
</mim:PrimitiefDatatype>
<mim:Attribuutsoort id="fietsenwinkel-contacten-bankrekening-rekeningnummer">
...
<mim:type>
<mim-ref:DatatypeRef xlink:href="#fietsenwinkel-contacten-iban">IBAN</mim-ref:DatatypeRef>
</mim:type>
...
</mim:Attribuutsoort>
XLink is not supported by JAXB. Therefore all RefType
classes (that are a mapping of the schema type mim:RefType
) have a subclass RefTypeEx
with two helper methods:
public Object getTarget(); // To be used after loading a MIM serialization and traversing the model
public void setTarget(Object target); // To be used when constructing a new MIM model
A number of text fields in MIM (like Objecttype.definitie) can contain XHTML content. To support getting and setting XHTML as a string, all XhtmlText
classes have a subclass XhtmlTextEx
with two helper methods:
public void setContentAsString(String xhtml) throws MimSerializationApiXhtmlException;
public String getContentAsString() throws MimSerializationApiXhtmlException;
According to the MIM standard, the type of an attribuutsoort can be:
- One of the externally defined standard primitive datatype, like
CharacterString
,Integer
orDate
. - A reference to a
Primitief datatype
,Gestructureerd datatype
,Enumeratie
,Referentielijst
orCodelijst
that is defined in the model elsewhere. - A reference to a
Keuze
(a choice between datatypes). - A reference to a
Constructie
(part of the MIM extension mechanism).
To obtain the actual type using the JAXB generated classes involves calling a lot of different methods and following quite some references. For this reason every Attribuutsoort
can be cast to an AttribuutsoortEx
that provides one extra method:
public AttribuutsoortType getAttribuutsoortType();
AttribuutsoortType
is a marker interface that is implemented by the classes Datatype
, DatatypeAbstract
(and all its subclasses like PrimitiefDatatype
, Codelijst
and Referentielijst
), Keuze
and Constructie
(see AttribuutsoortType javadocs).
You can get the supertypes of an Objecttype
by casting the Objecttype
to ObjecttypeEx
and use the method:
public List<Objecttype> getSupertypen(boolean excludeStaticOrMixinTypes); // MIM 1.2+
or:
public List<Objecttype> getSupertypen(boolean excludeStaticTypes); // MIM 1.1.*
Using the parameter excludeStaticOrMixinTypes
or excludeStaticTypes
it is possible to filter out any non-direct "static" or "mixin" supertypes.
You can get the "inner" model elements of an Objecttype
by name by casting the Objecttype
to ObjecttypeEx
and use one of the methods:
public Attribuutsoort getAttribuutsoort(String name);
public Gegevensgroep getGegevensgroep(String name);
public Relatiesoort getRelatiesoort(String name);
public Keuze getKeuze(String name);
public Constraint getConstraint(String name);
public Kenmerk getKenmerk(String name);
The name is always case sensitive.
You get get any model element by unique identifier or name using the methods:
public Object getModelElementById(String id);
public List<Object> getModelElementsByName(String name);
of the MimModel
. Both the identifier and name are case sensitive.
Please create an Github issue when you need more of these utility/helper methods!
All model element Java classes implement the interface org.jvnet.jaxb.lang.Child
which has a method:
public Object getParent();
that can be used to get the parent object. If for example the method MimSerializationApi.getModelElementsByName()
was used to find an Objecttype
, this objecttype can be cast to
the Child
interface on which the getParent()
can be called to navigate to the package this objectype is part of.
See the sample application: LoadMimModel.java
A new MIM model can be created using the method MimSerializationApi.newModel
, for instance:
MimModel mimModel = MimSerializationApi.newModel(MIM_VERSION.VERSION_1_2, MIM_RELATIEMODELLERINGSTYPE.RELATIESOORT_LEIDEND);
In this example the mimModel will be of the class nl.geostandaarden.mim_1_2.relatiesoort.MimModel
.
After the model is created the (required) properties of the Informatiemodel
object can be set and new model elements can be added, for instance:
mimModel.setNaam("Mijn nieuwe model");
mimModel.setMIMTaal("NL");
// ... etc. ...
Informatiemodel.Packages packages = new Informatiemodel.Packages();
model.setPackages(packages);
Domein domeinContacts = new Domein();
packages.getDomein().add(domein);
domeinContacts.setNaam("Contacten")
domeinContacts.setId("domein-contacten");
// ... etc. ...
When constructing a new model, the RefTypeEx.getTarget()
methods and other functionality that relies on these methods, like getting the AttribuurtsoortType
of an Attribuutsoort
, can
only be used after the XLink references are indexed. This indexing can be triggered by calling the method:
public void indexReferences();
on the MimModel
object.
The generated Java classes also support a Fluent API. So for instance when constructing a model, a Domein could be constructed like this
Domein domein = new Domein();
domein.setId("mijn-domein-1");
domein.setNaam("Mijn Naam");
domein.setHerkomst("Dit is de herkomst");
XhtmlTextEx definitieText = new XhtmlTextEx();
definitieText.setContentAsString("<xhtml:body><xhtml:p>Dit is een tekst met <xhtml:b>mixed</xhtml:b> <xhtml:i>content</xhtml:i>.</xhtml:p></xhtml:body>");
domein.setDefinitie(definitieText);
domein.setHerkomstDefinitie("Dit is de herkomst van de definitie");
domein.setDatumOpname("2025-01-01");
but using the Fluent API also like this:
Domein domein = new Domein()
.withId("mijn-domein-1")
.withNaam("Mijn Naam")
.withHerkomst("Dit is de herkomst")
.withDefinitie(definitieText)
.withHerkomstDefinitie("Dit is de herkomst van de definitie")
.withDatumOpname("2025-01-01");
A MIM model can be saved (or "marshalled", "serialized") using the save
methods of MimModel
:
public void MimModel.save(OutputStream mimSerialization) throws MimSerializationApiSaveException;
or:
public void MimModel.save(Path mimSerializationPath) throws MimSerializationApiSaveException;
The API can also validate the MIM serialization against the MIM XML schema during save:
public void MimModel.save(OutputStream mimSerialization, ValidationEventHandler eventHandler) throws MimSerializationApiSaveException;
or:
public void MimModel.save(Path mimSerializationPath, ValidationEventHandler eventHandler) throws MimSerializationApiSaveException;
for instance:
mimModel.save(outputStream, new ValidationEventHandler() {
@Override
public boolean handleEvent(ValidationEvent event) {
System.out.println("Validation error: " + event.getMessage() + " (" + event.getSeverity() + ")");
return event.getSeverity() == ValidationEvent.WARNING;
}
});
See the sample application: SaveMimModel.java