Tutorial – Getting started with TRIMM JPA
This tutorial will take you through the process of creating a completely new Maven based Java project that uses TRIMM JPA to generated JPA (with support for Hibernate extension).
Prerequisites:
- Java 6 or later must be installed (we recommend installing Java 7)
- Maven 3 – must be installed on your computer (on OS X you can install it using HomeBrew‘s “
brew install maven
” command) - Recommended: IntelliJ IDEA or Eclipse (with the M2E plugin installed)
Step 1 – Create a TRIMM JPA enabled Maven project
Execute the following command through your commandline/terminal:
mvn archetype:generate -DarchetypeGroupId=dk.tigerteam.maven.archetypes -DarchetypeArtifactId=trimm.jpa.archetype
-DarchetypeVersion=1.0.0
-DarchetypeCatalog=http://www.tigerteam.dk/maven2/archetype-catalog.xml
and for this example we will provide the following values:
groupId | dk.tigerteam.trimm.examples |
artifactId | firstjpaproject |
version | 1.0-SNAPSHOT |
package | dk.tigerteam.trimm.examples.firstjpaproject |
Step 2 – Import the TRIMM enabled Maven project into your IDE
For IntelliJ follow the steps in this tutorial
Step 3 – Model your domain model in UML using Enterprise Architect (EA)
Follow the instructions here to model a simple Domain model that will be used for code generating a JPA entity model.
Step 4 Export your UML domain model to XMI
Follow the steps in this guide for Enterprise Architect.
Step 5 Configure the TRIMM JPA Maven plugin to generate sourcecode
The TRIMM JPA code generation functionality is defined in the projects Maven configuration file called pom.xml which is placed in the root of the project folder (e.g. C:\TRIMM-examples\firstjpaproject)
Within the pom.xml, inside the build/plugins section you will find the TrimmJpaMavenPlugin plugin
<plugin> <groupId>dk.tigerteam</groupId> <artifactId>TrimmJpaMavenPlugin</artifactId> <version>1.0.0</version> <executions> <execution> <id>generate</id> <phase>generate-sources</phase> <goals> <goal>generate</goal> </goals> <configuration> <yamlFile>model/JpaModel.yml</yamlFile> </configuration> </execution> </executions> </plugin>
You can see from the value inside the yamlFile the configuration file that is used to configure the TrimmJpaMavenPlugin plugin.
In this case it’s the JpaModel.yml which is placed inside the model folder of the project, together with our EA project file (FirstJPAModel.eap) and our XMI export from Step 4 (model.xml).
TRIMM JPA YAML configuration file
The TRIMM (currently) default configuration file is based on YAML which is a reading friendly file format.
Below is the complete configuration, JpaModel.yml, for our tutorial (everything with a # in front of it is a comment):
#Setup xmiModelPath: model/model.xml umlTool: EA basePackageName: dk.tigerteam.trimm.examples.firstjpaproject generateExtensionClasses: false # Paths generateBaseClassesToPath: target/generated-sources/domainmodel generateInterfacesToPath: target/generated-sources/domainmodel generateTestClassesToPath: target/generated-sources/generated-tests generateResourcesToPath: target/generated-sources/generated-resources mapUmlPropertyTypes: - name: LocalDate javaType: org.joda.time.LocalDate jpaTypeConverterClass: org.joda.time.contrib.hibernate.PersistentLocalDate # JPA Setup jpaSetup: addTableAndColumnNames: false defaultToLazyFetchingForAllAssociations: true rootMappedSuperClass: dk.tigerteam.trimm.examples.firstjpaproject.model.AbstractEntity # Extensions eventListeners: - dk.tigerteam.trimm.mdsd.java.generator.extension.BidirectionalGeneratorEventListener - dk.tigerteam.trimm.mdsd.java.generator.extension.SerialVersionUIDGeneratorListener - dk.tigerteam.trimm.mdsd.java.generator.extension.PropertySugarMethodsEventListener - dk.tigerteam.trimm.mdsd.jpa.Jpa2OrphanRemovalListener # Create Runtime Meta Model createRuntimeMetaModel: packageName: dk.tigerteam.trimm.examples.firstjpaproject.model.meta # Create JPA Integration tests for all entities createIntegrationTest: testClassName: CompleteModelIntegrationTest testPackageName: dk.tigerteam.trimm.examples.firstjpaproject.model extendsClass: dk.tigerteam.trimm.examples.firstjpaproject.model.BaseJpaModelTest autoHandleTransactionsAndResources: true
Explanation for the configuration parameters:
Parameter | Value | Explanation |
---|---|---|
xmiModelPath | dk.tigerteam.trimm.examples.firstjpaproject | The relative path to our XMI export file |
basePackageName | dk.tigerteam.trimm.examples.firstjpaproject | This package will pre-appended all generated packages, classes, interfaces, etc. Since we export the model package in EA this means that our Member, Offer, OfferType and ExpirationType will be generated into the package dk.tigerteam.trimm.examples.firstjpaproject.model |
generateExtensionClasses | false | Means that we will NOT generate using the Generator Gap pattern. This basically means that any changes you the developer would make to the generated code will be overwritten next time the TRIMM JPA plugin is run |
Parameter | Value | Explanation |
---|---|---|
generateBaseClassesToPath | target/generated-sources/domainmodel | When generating without the Generator Gap pattern, then most classes generated (except interfaces) qualify as Base classes. As can be seen, we generated to a java code subfolder of the target/generated-sources folder, which means that all generated code will be placed inside Mavens preferred location for intermediate code that isn’t checked into source control (which is recommended) |
generateInterfacesToPath | dk.tigerteam.trimm.examples.firstjpaproject | Any interfaces generated are placed in this java code folder (same as above) |
generateTestClassesToPath | false | Any test classes (i.e. code that doesn’t qualify as runtime code) gets generated to this java test code folder |
generateResourcesToPath | false | Any resources (such as text files, xml, orm.xml, etc) gets generated to this resource folder |
Parameter | Value | Explanation |
---|---|---|
name | LocalDate | The full name of an attribute/parameter type defined in the UML model |
javaType | org.joda.time.LocalDate | Describes which Java class to use when (in this case) LocalDate is used in the UML model |
jpaTypeConverterClass | org.joda.time.contrib.hibernate. PersistentLocalDate | Describes which Hibernate EnhancedUserType that should be used (is indicated in the generated code using @org.hibernate.annotations.Type – or if you use EclipseLink then it represents which @org.eclipse.persistence.annotations.Converter to use) |
Parameter | Value | Explanation |
---|---|---|
addTableAndColumnNames | false | This setting controls whether JPA defaults should apply or if TRIMM JPA should place @JoinTable, @Column, etc. annotations to control table and column mapping names. In this case we rely on JPA defaults |
defaultToLazyFetchingForAllAssociations | true | Here we force all JPA associations to be default lazy and thereby overrule JPA defaults |
rootMappedSuperClass | dk.tigerteam.trimm.examples. firstjpaproject.model.AbstractEntity | Here we insert a class of your choosing at the top of every inheritance hierarchy. In this case we chose a hand written class called AbstractEntity, which in our example defines @Id field |
Listener | Explanation |
---|---|
BidirectionalGeneratorEventListener | This listener will insert code into property accessors (e.g. getOrder() or getOrderLinesCollection()) that will ensure that associations that are defined as bi-directional in your UML also support that same in-memory (e.g. so customer.setAddress(address), will ensure that the generated code will call address.setCustomer(inverseCustomer) so that both customer and address have a pointer to each other in memory) |
SerialVersionUIDGeneratorListener | This listener will generate a private static final long serialVersionUID field in every generated class |
PropertySugarMethodsEventListener | This listener will generate fluent interface methods such as withXxxx or addToXxxxCollection properties |
Jpa2OrphanRemovalListener | This listener will investigate the UML model and in case associations adhere to the JPA rules of Orphan Removal, then a @OrphanRemoval annotation will be applied automatically |
Parameter | Value | Explanation |
---|---|---|
packageName | dk.tigerteam.trimm.examples. firstjpaproject.model.meta | This parameter control under which package the RuntimeMetaModel should be generated |
Parameter | Value | Explanation |
---|---|---|
testClassName | CompleteModelIntegrationTest | Determines the name of the JUnit 4 class which control the test of all Entities in the Model |
testPackageName | dk.tigerteam.trimm.examples. firstjpaproject.model | Determines under which package te testClassName (in our case CompleteModelIntegrationTest) will be placed. |
extendsClass | dk.tigerteam.trimm.examples. firstjpaproject.model.BaseJpaModelTest | Determines which hand written class to extend from. This class control initialization of the JPA EntityManagerFactory/EntityManager. The only requirement is that the class inherits from dk.tigerteam.trimm.persistence.mdsd. test.AbstractModelTest |
autoHandleTransactionsAndResources | true | Control whether the code that’s generated into the testClassName (in our case CompleteModelIntegrationTest) should control transactions (begin and rollback) |
This configuration section control whether a Runtime version of the MetaModel (that’s a representation of the UML model) will be generated.Explanation for the Create JPA Integration tests for all entities configuration parameters.
This section controls whether a complete JUnit 4 test suite, that integration tests the generated JPA model against a database of your choice, will be generated.
5.1 – Completing the configuration with handwritten classes
Before we can complete the code generation part for this example we need to provide implementations for the handwritten classes we specified in the configuration, specifically the JPA rootMappedSuperClass and JPA Unit test extendsClass.
5.1.1 – Provide the TRIMM JPA RootMappedSuperClass
In the IDE select the src/main/java folder (see picture for IDEA) and select New Package dk.tigerteam.trimm.examples.firstjpaproject.model
After this add Class AbstractEntity to the newly created dk.tigerteam.trimm.examples.firstjpaproject.model package:
Paste the following content into the newly created AbstractEntity class:
package dk.tigerteam.trimm.examples.firstjpaproject.model; import javax.persistence.*; @MappedSuperclass public class AbstractEntity { @Id @SequenceGenerator(name = "FIRST_JPA_GEN", sequenceName = "FIRST_JPA_SEQ") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FIRST_JPA_GEN") private Long id; public Long getId() { return id; } }
5.1.2 – Provide the TRIMM JPA Unit test ExtendsClass
In the IDE select the src/test/java (as we’re creating test related code) and select New Package dk.tigerteam.trimm.examples.firstjpaproject.model:
After this add Class BaseJpaModelTest to the newly created dk.tigerteam.trimm.examples.firstjpaproject.model package:
Paste the following content into the newly created BaseJpaModelTest:
package dk.tigerteam.trimm.examples.firstjpaproject.model; import dk.tigerteam.trimm.mdsd.runtime.RuntimeMetaClazz; import dk.tigerteam.trimm.mdsd.runtime.RuntimeMetaProperty; import dk.tigerteam.trimm.persistence.mdsd.test.AbstractModelTest; import dk.tigerteam.trimm.persistence.mdsd.test.RuntimeMetaTestDataCreator; import dk.tigerteam.trimm.persistence.util.HibernateProxyHandler; import dk.tigerteam.trimm.persistence.util.ObjectPrinter; import dk.tigerteam.trimm.persistence.util.ProxyHandler; import dk.tigerteam.trimm.util.IndentPrintWriter; import org.joda.time.LocalDate; import org.junit.AfterClass; import org.junit.BeforeClass; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import java.lang.reflect.Field; import java.util.Set; public class BaseJpaModelTest extends AbstractModelTest { private static EntityManagerFactory emf; @BeforeClass public static void setup() { emf = Persistence.createEntityManagerFactory("firstjpamodel"); } @AfterClass public static void teardown() { emf.close(); } @Override public EntityManager getEntityManager() { return emf.createEntityManager(); } @Override public ProxyHandler getProxyHandler(EntityManager entityManager) { return new HibernateProxyHandler(entityManager); } @Override public Field[] getIgnoreFieldsDuringGraphCompare(Class<?> aClass) { return new Field[0]; } // Support for pretty printing tests errors that contain LocalDate @Override public ObjectPrinter[] getObjectPrinters() { return new ObjectPrinter[]{new ObjectPrinter() { @Override public boolean support(Object object) { return object instanceof LocalDate; } @Override public void print(Object object, Set<Object> printedObjects, IndentPrintWriter printWriter) { printWriter.print(((LocalDate) object).toString()); } }}; } // Support for LocalDate in test data @Override protected RuntimeMetaTestDataCreator lazyCreateDataCreator() { return new RuntimeMetaTestDataCreator() { @Override protected Object newInstance(RuntimeMetaClazz metaClazz, ObjectInstancesStack objectInstancesStack, RuntimeMetaProperty metaProperty) { Class<?> _class = metaClazz.getJavaClass(); if (_class != null && LocalDate.class.equals(_class)) { return new LocalDate(); } else { return super.newInstance(metaClazz, objectInstancesStack, metaProperty); } } }; } }
The first thing to notice is the public static void setup() method where we initialize a JPA EntityManagerFactory for a PersistenceUnit called “firstjpamodel”.
This PersistenceUnit needs to be configured, otherwise the unit test wont pass.If you want to use the same PersistenceUnit configuration for both test and normal runtime purposes, then you should place your persistence.xml file in src/main/resources/META-INF otherwise, as for this example, we will define a special unit test PersistenceUnit configuration that uses an in memory database (H2) during testing. For this purpose, we place our persistence.xml in src/test/resources/META-INF.First you need to create the META-INF folder inside the src/test/resources folder. Select the src/test/resources folder and choose New Package META-INF (don’t mind that IDEA complains about invalid package name – just ignore the warning and press OK):
Create a file called persistence.xml (which is the default filename for JPA PersistenceUnit configurations). Choose the src/test/resources/META-INF folder/package and select New File persistence.xml:
Paste the following content into the newly created persistence.xml file: org.hibernate.ejb.HibernatePersistence META-INF/orm.xml true This configures JPA to use Hibernate as provider and use the H2 database in an in-memory mode.Final step – Enable additional Maven dependenciesTo complete the configuration we need to enable additional Maven dependencies in the pom.xml file, so that we can use Hibernate, H2, etc.Open pom.xml and uncomment additional dependencies that are currently commented out.
The complete pom.xml should look like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>dk.tigerteam.trimm.examples</groupId> <artifactId>firstjpaproject</artifactId> <version>1.0-SNAPSHOT</version> <name>firstjpaproject</name> <url>trimm.tigerteam.dk</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <default.encoding>UTF-8</default.encoding> <default.jdk.version>1.6</default.jdk.version> <hibernate.version>3.6.10.Final</hibernate.version> </properties> <dependencies> <dependency> <groupId>dk.tigerteam</groupId> <artifactId>TrimmCore</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>dk.tigerteam</groupId> <artifactId>TrimmJpa</artifactId> <version>1.0.0</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.3.173</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time-hibernate</artifactId> <version>1.3</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator-legacy</artifactId> <version>4.0.2.GA</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>${default.jdk.version}</source> <target>${default.jdk.version}</target> <encoding>${default.encoding}</encoding> </configuration> </plugin> <plugin> <groupId>dk.tigerteam</groupId> <artifactId>TrimmJpaMavenPlugin</artifactId> <version>1.0.0</version> <executions> <execution> <id>generate</id> <phase>generate-sources</phase> <goals> <goal>generate</goal> </goals> <configuration> <yamlFile>model/JpaModel.yml</yamlFile> </configuration> </execution> </executions> </plugin> </plugins> </build> <repositories> <repository> <id>tigerteam-maven2-repository</id> <name>tigerteam.dk Repository for Maven 2</name> <url>http://www.tigerteam.dk/maven2/</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>tigerteam-maven2-repository</id> <name>tigerteam.dk Repository for Maven 2</name> <url>http://www.tigerteam.dk/maven2/</url> </pluginRepository> </pluginRepositories> </project>
Step 6 Generate code using TRIMM JPA
After you have completed Step 1 to 5 you now have a completely configured TRIMM JPA project.
From here on, you can make small changes to the UML model (and re-export) or to the configuration and complete the code generation phase as often as you want.So let’s get to it, to generate code you run at least the maven generate-sources lifecycle (i.e. if you run any lifecycle after that such as compile, test, package or install then code will also be generated) mvn generate-sources This will look something like this
(note the long generation time is due to downloading of latest Maven snapshots, which can be turned off)But since we used an IDE for all the other things we didn’t, we could also use the IDE for initiating the code generation.
Since we configured TRIMM JPA to use maven source- and resource-folders the easiest way to generate code from within IntelliJ IDEA and also have IDEA configure source folders for the IDE project is to right click the root of the project, select Maven > Generate Sources and Update Folders:
After completing this step the IDEA project should have the following configuration/source/test folders:
Step 7 – Running the generated JPA Unit test
To verify that all code generated is working and all JPA code and mappings are correct, we can execute the generated JPA Unit test (which is an integration test as it works against an external resource – the database).
To do this either run (from the command line): mvn test Or select the CompleteModelIntegrationTest in target/generated-sources/generated-tests/dk.tigerteam.trimm.examples.firstjpaproject.model and choose Run.. in IDEA:
The result should look like this:
Step 8 – Taking it one step further – using Generator Gap/Extension Classes pattern (optional)
This step is optional, but sometimes it’s nice or even necessary to be able to add code to generated source code.
Editing generated sourcecode by hand is bad practice – your changes will be overwritten the next time you generate. Instead you should apply the Generator Gap pattern – which is called Extension Classes in TRIMM Java/JPA
To enable Extension Classes (Generator Gap Pattern) for TRIMM JPA all you need to do is add the following configurations to the JpaModel.yml configuration file:
- Change generateExtensionClasses to true
- Add addExtensionAndBaseClassAnnotations: true to the same Setup section. These annotations are required by the JPA Unit test code
- Add generateExtensionClassesToPath: src/main/domainmodel-extensions to the Paths section. This will ensure that extension classes (the concrete classes that you can hand edit) are generated to a folder inside src/main so that it can come under source control.
- Add makeBaseClassesIntoMappedSuperClassesIfPossible: true to the JPA Setup section. This will optimize JPA inheritance mapping code, so that real Abstract classes don’t consume additional tables in case you later opt for another inheritance scheme than Single table.
The complete configuration is show here:
#Setup xmiModelPath: model/model.xml umlTool: EA basePackageName: dk.tigerteam.trimm.examples.firstjpaproject generateExtensionClasses: true addExtensionAndBaseClassAnnotations: true # Paths generateBaseClassesToPath: target/generated-sources/domainmodel generateExtensionClassesToPath: src/main/domainmodel-extensions generateInterfacesToPath: target/generated-sources/domainmodel generateTestClassesToPath: target/generated-sources/generated-tests generateResourcesToPath: target/generated-sources/generated-resources mapUmlPropertyTypes: - name: LocalDate javaType: org.joda.time.LocalDate jpaTypeConverterClass: org.joda.time.contrib.hibernate.PersistentLocalDate # JPA Setup jpaSetup: addTableAndColumnNames: false makeBaseClassesIntoMappedSuperClassesIfPossible: true generatePresentFieldInEmbeddables: false defaultToLazyFetchingForAllAssociations: true rootMappedSuperClass: dk.tigerteam.trimm.examples.firstjpaproject.model.AbstractEntity # Extensions eventListeners: - listener: dk.tigerteam.trimm.mdsd.java.generator.extension.BidirectionalGeneratorEventListener - listener: dk.tigerteam.trimm.mdsd.java.generator.extension.SerialVersionUIDGeneratorListener - listener: dk.tigerteam.trimm.mdsd.java.generator.extension.PropertySugarMethodsEventListener - listener: dk.tigerteam.trimm.mdsd.jpa.Jpa2OrphanRemovalListener # Create Runtime Meta Model createRuntimeMetaModel: packageName: dk.tigerteam.trimm.examples.firstjpaproject.model.meta # Create JPA Integration tests for all entities createIntegrationTest: testClassName: CompleteModelIntegrationTest extendsClass: dk.tigerteam.trimm.examples.firstjpaproject.model.BaseJpaModelTest testPackageName: dk.tigerteam.trimm.examples.firstjpaproject.model autoHandleTransactionsAndResources: true
Parameter | Value | Explanation |
---|---|---|
xmiModelPath | dk.tigerteam.trimm.examples.firstjpaproject | The relative path to our XMI export file |
basePackageName | dk.tigerteam.trimm.examples.firstjpaproject | This package will pre-appended all generated packages, classes, interfaces, etc. Since we export the model package in EA this means that our Member, Offer, OfferType and ExpirationType will be generated into the package dk.tigerteam.trimm.examples.firstjpaproject.model |
generateExtensionClasses | false | Means that we will NOT generate using the Generator Gap pattern. This basically means that any changes you the developer would make to the generated code will be overwritten next time the TRIMM JPA plugin is run |
Parameter | Value | Explanation |
---|---|---|
generateBaseClassesToPath | target/generated-sources/domainmodel | When generating without the Generator Gap pattern, then most classes generated (except interfaces) qualify as Base classes. As can be seen, we generated to a java code subfolder of the target/generated-sources folder, which means that all generated code will be placed inside Mavens preferred location for intermediate code that isn’t checked into source control (which is recommended) |
generateInterfacesToPath | dk.tigerteam.trimm.examples.firstjpaproject | Any interfaces generated are placed in this java code folder (same as above) |
generateTestClassesToPath | false | Any test classes (i.e. code that doesn’t qualify as runtime code) gets generated to this java test code folder |
generateResourcesToPath | false | Any resources (such as text files, xml, orm.xml, etc) gets generated to this resource folder |
Parameter | Value | Explanation |
---|---|---|
name | LocalDate | The full name of an attribute/parameter type defined in the UML model |
javaType | org.joda.time.LocalDate | Describes which Java class to use when (in this case) LocalDate is used in the UML model |
jpaTypeConverterClass | org.joda.time.contrib.hibernate. PersistentLocalDate | Describes which Hibernate EnhancedUserType that should be used (is indicated in the generated code using @org.hibernate.annotations.Type – or if you use EclipseLink then it represents which @org.eclipse.persistence.annotations.Converter to use) |
Parameter | Value | Explanation |
---|---|---|
addTableAndColumnNames | false | This setting controls whether JPA defaults should apply or if TRIMM JPA should place @JoinTable, @Column, etc. annotations to control table and column mapping names. In this case we rely on JPA defaults |
defaultToLazyFetchingForAllAssociations | true | Here we force all JPA associations to be default lazy and thereby overrule JPA defaults |
rootMappedSuperClass | dk.tigerteam.trimm.examples. firstjpaproject.model.AbstractEntity | Here we insert a class of your choosing at the top of every inheritance hierarchy. In this case we chose a hand written class called AbstractEntity, which in our example defines @Id field |
Listener | Explanation |
---|---|
BidirectionalGeneratorEventListener | This listener will insert code into property accessors (e.g. getOrder() or getOrderLinesCollection()) that will ensure that associations that are defined as bi-directional in your UML also support that same in-memory (e.g. so customer.setAddress(address), will ensure that the generated code will call address.setCustomer(inverseCustomer) so that both customer and address have a pointer to each other in memory) |
SerialVersionUIDGeneratorListener | This listener will generate a private static final long serialVersionUID field in every generated class |
PropertySugarMethodsEventListener | This listener will generate fluent interface methods such as withXxxx or addToXxxxCollection properties |
Jpa2OrphanRemovalListener | This listener will investigate the UML model and in case associations adhere to the JPA rules of Orphan Removal, then a @OrphanRemoval annotation will be applied automatically |
Parameter | Value | Explanation |
---|---|---|
packageName | dk.tigerteam.trimm.examples. firstjpaproject.model.meta | This parameter control under which package the RuntimeMetaModel should be generated |
Parameter | Value | Explanation |
---|---|---|
testClassName | CompleteModelIntegrationTest | Determines the name of the JUnit 4 class which control the test of all Entities in the Model |
testPackageName | dk.tigerteam.trimm.examples. firstjpaproject.model | Determines under which package te testClassName (in our case CompleteModelIntegrationTest) will be placed. |
extendsClass | dk.tigerteam.trimm.examples. firstjpaproject.model.BaseJpaModelTest | Determines which hand written class to extend from. This class control initialization of the JPA EntityManagerFactory/EntityManager. The only requirement is that the class inherits from dk.tigerteam.trimm.persistence.mdsd. test.AbstractModelTest |
autoHandleTransactionsAndResources | true | Control whether the code that’s generated into the testClassName (in our case CompleteModelIntegrationTest) should control transactions (begin and rollback) |
When you run mvn generate-sources or select IntelliJ IDEA’s Maven > Generate Source and Update Folders option, then the result should look like this:
It’s now possible to go into the concrete classes and add custom logic.