Contents:
This guide builds on the information already covered in the Quick Start and Basic Configuration pages.
Much of RevGen's capabilities comes from the underlying JavaGen Agile framework. JavaGen Agile defines the model architectures, naming pattern mechanisms and code generation framework. To understand the underlying classes please see the JavaGen Agile User's Guide.
RevGen itself is just a collection of templates, a configuration file and a few classes specific to converting database schemas to Java. This guide focuses on RevGen-specific configuration.
RevGen configuration is largely handled by two files:
Both files are located in src/revgen and depending on your needs you can you use any combination of the two. By default revgen.properties is loaded from the src/revgen folder and RevGenSpringConfig.xml is loaded from the classpath (i.e. the RevGen jar file).
The configuration to load both files from the src/revgen folder looks like this in Maven 2:
<plugin>
<groupId>org.javagen.revgen</groupId>
<artifactId>maven-revgen-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals><goal>revgen</goal></goals>
<configuration>
<propertyFile>file:src/revgen/revgen.properties</propertyFile>
<configFile>file:src/revgen/RevGenSpringConfig.xml</configFile>
</configuration>
</execution>
</executions>
</plugin>And this in Ant:
<target name="revgen" depends="" unless="skipgen" description="RevGen code generator">
<java classname="org.javagen.light.revgen.SpringMain" fork="true" failonerror="yes" classpathref="lib.path">
<arg value="file:src/revgen/RevGenSpringConfig.xml"/>
<arg value="file:src/revgen/revgen.properties"/>
</java>
</target>Any type of configuration can be achieved using src/revgen/RevGenSpringConfig.xml including:
Much of the configuration in this document is done using this file. Becoming familiar with its contents will give you complete control over RevGen.
Database properties are set using:
dbDriverClassName = org.hsqldb.jdbcDriver dbUsername = sa dbPassword = dbUrl = jdbc:hsqldb:hsql://localhost/contact # this is just needed by Hibernate at runtime: hibernateDialect = org.hibernate.dialect.HSQLDialect
You can also substitute RevGen's DriverManagerDataSource for your own DataSource. For example this works:
<bean id="dataSource" class="org.hsqldb.jdbc.jdbcDataSource">
<property name="database" value="${dbUrl}"/>
<property name="user" value="${dbUsername}"/>
<property name="password" value="${dbPassword}"/>
</bean>Tables to process can can be limited using:
includeTables = ADRRESS, CITY, STATE, COUNTRY excludeTables = INVENTORY_STAGING, SALES_STAGING
If your tables have plural names, you should set pluralTableNames to true.
If the names are not converted to singular nouns correctly, you can list them explicitly using the pluralisation bean:
<bean name="pluralisation" class="org.javagen.agile.oo.naming.RegularPlurals"/>
<property name="singularToPlural">
<map>
<entry key="Child" value="Children""/>
</map>
</property>
</bean>Finally table names will be converted to uppercase if tableNamesToUpperCase is true.
The code generator can be configured to generate several types of output. Here are properties and their settings:
# Valid DAO implementation types (daoImplType): hibernate, spring, jpa daoImplType = jpa # annotations: true, false annotations = true # junitVersion: 3, 4 junitVersion = 4 # emit Hibernate validation annotations: true, false hibernateValidation = true # overrides one-time generation checks (overwriteAll): true, false overwriteAll = true
Most of these properties are self documenting. If you set annotations to false, you will generate XML database mapping files.
annotations = false
Round Tripping refers to the ability to freely mix hand written and generated code throughout the development process. Although RevGen does not currently support, merging both within a single file, several alternatives techniques are supported that achieve the same goals. These techniques can be combined as needed to achieve the desired level of round trip configuration.
Many code generation artifacts are only emitted if they don't already exist. You can safely edit these files and they won't be overwritten (see Conditional Template Emission).
By default RevGen generates a single model class for each entity, but it can be configured to generate two classes:
extensionByInheritance = true
genEntityNameTemplate = #{modelName}GenThis will result in a empty class being emitted that looks something like this:
public class Person extends PersonGen { ... }Person can be extended with hand-written code without interfering with the generated class, PersonGen.
The RevGen plugin can be configured to separate generated from hand written code, for example:
<plugin>
<groupId>org.javagen.revgen</groupId>
<artifactId>maven-revgen-plugin</artifactId>
<configuration>
<propertyFile>file:src/revgen/revgen.properties</propertyFile>
<sourceDirectory>${pom.build.directory}/generated-sources/revgen-main</sourceDirectory>
<testSourceDirectory>${pom.build.directory}/generated-sources/revgen-test</testSourceDirectory>
<resourceDirectory>${project.build.directory}/generated-sources/revgen-resources</resourceDirectory>
</configuration>
</plugin>As another option, the RevGen plugin can remove duplicate files, allowing any generated file to be modified simply by copying it from the generated directory to the hand-coded directory. Just set removeDuplicates to true:
<plugin>
<groupId>org.javagen.revgen</groupId>
<artifactId>maven-revgen-plugin</artifactId>
<configuration>
<propertyFile>file:src/revgen/revgen.properties</propertyFile>
<sourceDirectory>${pom.build.directory}/generated-sources/revgen</sourceDirectory>
<testSourceDirectory>${pom.build.directory}/generated-sources/revgen-test</testSourceDirectory>
<removeDuplicates>true</removeDuplicates>
</configuration>
</plugin>Default properties are defined on the RevGenPropertyPlaceholderConfigurer bean within the RevGenSpringConfig.xml file and can be overridden by using the revgen.properties file.
The resulting properties are injected into the root model (defaultsModel) which makes them available to the entire model tree as well as the templates.
Contexts (i.e. maps of key-value pairs) can be attached to model instances and even template emitters. Because models are arranged into a tree structure, global attributes can be shared from the root node or overridden by local nodes. The context visible at template invocation is the combination of the current context (leaf) down through the parent chain to the root with child values taking precedence over parent values. Thus by using grouping strategies, you can control the processing environment of whole collections of nodes.
The overall behavior of RevGen is controlled by the GeneratorPipeline which implements a code generation pipeline or assembly line. Having a pipelined architecture makes it easy to customize code generation behavior by adding and removing task-specific modules called Generators.
To give you a sense of how to manipulate the pipeline to suite your needs, here are a few examples using predefined components in the RevGenSpringConfig.xml file:
<bean id="pipeline" class="org.javagen.agile.core.GeneratorPipeline">
<property name="pipeline">
<list>
<ref bean="dbLoader"/>
<ref bean="db2ooPass1"/>
<ref bean="db2ooPass2"/>
<bean class="org.javagen.revgen.visitor.PostProcessVisitor"/>
<bean class="org.javagen.agile.core.visitor.DefaultValueVisitor"/>
<ref bean="emitterVisitor"/>
</list>
</property>
</bean><bean id="pipeline" class="org.javagen.agile.core.GeneratorPipeline">
<property name="pipeline">
<list>
<ref bean="dbLoader"/>
<bean class="org.javagen.revgen.visitor.IdAssignerDb2OO"/>
<bean class="org.javagen.agile.core.visitor.IndexBuilderVisitor"/>
<ref bean="writeMetadata"/>
</list>
</property>
</bean><bean id="pipeline" class="org.javagen.agile.core.GeneratorPipeline">
<property name="pipeline">
<list>
<bean class="org.javagen.revgen.core.xml.JAXBXmlReader">
<property name="xmlFile" value="src/revgen/database-model.xml"/>
</bean>
<ref bean="db2ooPass1"/>
<ref bean="db2ooPass2"/>
<bean class="org.javagen.revgen.visitor.PostProcessVisitor"/>
<bean class="org.javagen.agile.core.visitor.DefaultValueVisitor"/>
<ref bean="emitterVisitor"/>
</list>
</property>
</bean><bean id="pipeline" class="org.javagen.agile.core.GeneratorPipeline">
<property name="pipeline">
<list>
<ref bean="dbLoader"/>
<ref bean="db2ooPass1"/>
<bean class="org.javagen.revgen.visitor.IdAssignerDb2OO"/>
<bean class="org.javagen.agile.core.visitor.IndexBuilderVisitor"/>
<ref bean="readAndMergeClassMetadata"/>
<ref bean="db2ooPass2"/>
<bean class="org.javagen.revgen.visitor.PostProcessVisitor"/>
<bean class="org.javagen.agile.core.visitor.DefaultValueVisitor"/>
<ref bean="emitterVisitor"/>
</list>
</property>
</bean>A few things to note are:
Most persistence frameworks can transparently manage association tables, completely hiding the foreign key management from the Java developer. The trade-off is that the Java developer can't access the values in this association table. In an association table that only consists of two foreign keys, this is not normally an issue, but if extra columns exist (like Timestamps, etc.) then these values are not visible.
By default RevGen is configured to identify many-to-many association tables and hide them in the mapping details:
<bean class="org.javagen.agile.db.visitor.LinkTableFinderVisitor">
<property name="relativeInputPath" value="DATABASE"/>
</bean>To map association tables as entities, simply comment out the LinkTableFinderVisitor from the pipeline.
To individually assign association tables, set linkTable to true in the merge-metadata.xml file:
<table linkTable="true" id="db:PERSONS_BANKS"/>
and configure an instance of IdOverrideVisitor to run before the database-to-Java transformation in the pipeline.
To modify or add templates, the first step is to copy the default templates from the RevGen jar file into a local directory. There is an ant task, getTemplates, to automate this task.
Then configure RevGen to use the local copies:
templateBasePath = file:src/revgen/freemarker/java
Both Freemarker FreemarkerCodeGenerator and Velocity VelocityCodeGenerator template engines are currently supported.
Individual templates are configured using a TemplateEmitter:
<bean id="pk" class="org.javagen.agile.core.emitter.TemplateEmitter">
<property name="sourceDirectoryProperty" value="#{srcDirectory}"/>
<property name="relativeFilePathProperty" value="#{entityPackageNameTemplate}/#{modelName}.java"/>
<property name="templatePath" value="orm/PK.java.ftl"/>
<property name="templateGenerator" ref="freemarkerGenerator"/>
</bean>In addition, they must be bound to specific model types. In this case, to any model instance with a "pk" modelType:
<bean id="binder" class="org.javagen.agile.core.emitter.binding.ModelTypeBinder">
<property name="emitterBindings">
<map>
<entry key="pk">
<set>
<ref bean="pk"/>
</set>
</entry>
</map>
</property>
</bean>Generated artifact emission can be made conditional. The fileDoesNotExist condition is defined to only allow one-time generation of artifacts. It can be added to a TemplateEmitter with the following line:
<property name="emitCondition" ref="fileDoesNotExist"/>
You can also trigger emission to property settings. For example:
<property name="emitCondition">
<bean class="org.javagen.agile.core.emitter.logic.Equals">
<constructor-arg value="${mappingType}"/>
<constructor-arg value="hbm"/>
</bean>
</property>