Core model generation

The Nemesis Platform is designed to be completely modular. Users must have the freedom to write their own modules which they can later plug -in, -out or simply swap each other. To achieve this, we use extensively Spring Framework, where services are simply registered as Spring beans and can be overridden by providing a custom bean with the same name.

However, one major issue still stands - how to achieve modularity on database level. Ideally, we would like to be able to specify an entity type in one module, then add attributes to that entity in multiple other modules. One way to achieve this is to simply extend the JPA entity and add the new attributes in the extended class. However, when we hand over the platform to the client, he/she will struggle to find which class actually extends which one. So to solve this problem we have introduced the notion of a Definition.

Introducing Definition-s in the Nemesis Platform, we achieve modularity on database level.

Definition

A Definition is an interface with the @Definition annotation, which specifies also getters/setters with JPA annotations. The @Definition annotation has the following attributes: idDiscriminator, name, definition, isAbstract, weight, inheritanceStrategy.

  • idDiscriminator - defines the idDiscriminator for the generated entity and also denotes that this entity will be stored in a separate table;

  • name - specifies the JPA entity name and the table name (if idDiscriminator is present);

  • definition - specifies which other definition this definition will add attributes to;

  • isAbstract - the attribute is pretty straight-forward;

  • weight - related to the way the definition is rendered in the backend console;

  • inheritanceStrategy - specifies which JPA inheritance strategy must be used.

Code model generation

So, to solve our modularity problem, all we have to do is in moduleA to specify an entity definition MyEntityDefinition

@Definition
public interface MyEntityDefinition {

        @Column
        String getName();

        void setName(String name);

}

Then, in every other module, we can specify an entity definition MyEntityDefinition (annotated with @Definition(definition=MyEntityDefinition.class)).

@Definition(definition = MyEntityDefinition.class)
public interface MyEntityDefinition extends MyEntityDefinition {

        @Column(name = "prop")
        Long getProperty();

        void setProperty(Long property);

}

Then, in our services, we can operate with the Definition interface. During compilation on the client side, the Nemesis Platform will make sure it creates a concrete class that implements all the definition interfaces:

@Entity
public class MyEntity implements MyEntityDefinition, MyEntityDefinitionX, MyEntityDefinitionY, .... {

        @Column
        private String name;

        @Column(name = "prop")
        private Long property;

        /* getters/setters */
        ...
}

and copies all the getter/setter methods in the concrete class.