Sunday, May 20, 2012

RigaJUG - Demo 1 - JPA2

First Demo of RigaJUG agenda.
This demo presents the track JPA2 of minuteproject. 

Starting from a simple model that holds translation information.
Minuteproject will generate a JPA2 layer.

This demo will illustrate:
  • Generation by console or via config file
  • Altering generated code to add JSR 303 (validation) annotation.
  • Writing a unit test
  • Enrichment facilities and customisation
Prerequisits
  • Download Minuteproject last version
  • Java 6 in path
  • Maven in path
  • Install model on myql
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

DROP SCHEMA IF EXISTS `tranxy` ;
CREATE SCHEMA IF NOT EXISTS `tranxy` DEFAULT CHARACTER SET latin1 ;
USE `tranxy` ;

-- -----------------------------------------------------
-- Table `tranxy`.`translation_key`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `tranxy`.`translation_key` ;

CREATE  TABLE IF NOT EXISTS `tranxy`.`translation_key` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT ,
  `key_name` VARCHAR(200) NULL DEFAULT NULL ,
  `description` VARCHAR(400) NULL DEFAULT NULL ,
  PRIMARY KEY (`id`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `tranxy`.`language`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `tranxy`.`language` ;

CREATE  TABLE IF NOT EXISTS `tranxy`.`language` (
  `idlanguage` INT(11) NOT NULL AUTO_INCREMENT ,
  `code` VARCHAR(45) NOT NULL ,
  PRIMARY KEY (`idlanguage`) ,
  UNIQUE INDEX `code_UNIQUE` (`code` ASC) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `tranxy`.`traduction`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `tranxy`.`traduction` ;

CREATE  TABLE IF NOT EXISTS `tranxy`.`traduction` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT ,
  `translation` VARCHAR(800) NULL DEFAULT NULL ,
  `language_id` INT(11) NOT NULL ,
  `Key_id` BIGINT(20) NOT NULL ,
  PRIMARY KEY (`id`) ,
  INDEX `fk_traduction_language` (`language_id` ASC) ,
  INDEX `fk_traduction_Key1` (`Key_id` ASC) ,
  CONSTRAINT `fk_traduction_Key1`
    FOREIGN KEY (`Key_id` )
    REFERENCES `tranxy`.`translation_key` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_traduction_language`
    FOREIGN KEY (`language_id` )
    REFERENCES `tranxy`.`language` (`idlanguage` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;



SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Console generation

By console

In /application run
>start-console.cmd/sh
Fill the 'Data model reverse-engineering' tab
And click on generate

The output goes in /output/trans/JPA2
To build the resulting package execute
>mvn clean package

By command line

Add configuration in /mywork/config
TRANXY-JPA2-1.xml
<!DOCTYPE root>
<generator-config xmlns="http://minuteproject.sf.net/xsd/mp-config" 
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" 
xs:noNamespaceSchemaLocation="../config/mp-config.xsd">
 <configuration>
  <conventions>
   <target-convention type="enable-updatable-code-feature" />
  </conventions>
  <model name="tranxy" version="1.0" package-root="net.sf.mp.demo">
   <data-model>
    <driver name="mysql" version="5.1.16" groupId="mysql"
     artifactId="mysql-connector-java"></driver>
    <dataSource>
     <driverClassName>org.gjt.mm.mysql.Driver</driverClassName>
     <url>jdbc:mysql://127.0.0.1:3306/tranxy</url>
     <username>root</username>
     <password>mysql</password>
    </dataSource>
    <primaryKeyPolicy oneGlobal="false" >
     <primaryKeyPolicyPattern name="autoincrementPattern"></primaryKeyPolicyPattern>
    </primaryKeyPolicy>
   </data-model>
   <business-model>
    <business-package default="tranxy">
     <condition type="package" startsWith="trans" result="translation"></condition>
    </business-package>
    <enrichment>
     <conventions>
      <!-- manipulate the structure and entities BEFORE manipulating the 
       entities -->
      <column-naming-convention type="apply-strip-column-name-suffix"
       pattern-to-strip="ID" />
      <reference-naming-convention
       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" />
     </conventions>
    </enrichment>
   </business-model>
  </model>
  <targets>
   <target refname="JPA2" fileName="mp-template-config-JPA2.xml"
    outputdir-root="../../dev/latvianjug/output/JPA2" templatedir-root="../../template/framework/jpa">
    <property name="add-querydsl" value="2.1.2"></property>
    <property name="add-jpa2-implementation" value="hibernate"></property>
    <property name="environment" value="remote"></property>
   </target>
      <target refname="CACHE-LIB" fileName="mp-template-config-CACHE-LIB.xml"
          templatedir-root="../../template/framework/cache">
      </target>
   <target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"
    templatedir-root="../../template/framework/bsla">
   </target>
  </targets>
 </configuration>
</generator-config>

Execute by running:
> model-generation.cmd/sh TRANXY-JPA2-1.xml
The ouput goes in /dev/latvianjug/output/JPA2

Make a build:
>mvn clean package

Console vs. Command line generation

The generation made by the command line has more enrichment facilities than just working via the console.
Example: here the configuration add querydsl integration.
The rest of the demo will focus on the configuration enrichment facilities.
Remark:
Ideally the console should move into a IDE plugin manipulating the configuration.

Resulting artefacts

Summary
  • A maven pom project
  • 3 JPA2 entities (one for each table)
Pom artefact
  • provide a jar with name and version number given in configuration
  • has hibernate, querydsl, mysql driver, junit dependencies
JPA2 entities
  • packaged logically entity starting with 'trans' goes to package translation other goes to 'tranxy' package
  • convention 'apply-strip-column-name-suffix' when ending with 'ID'
    • DB naming convention used (the foreign key name is composed of the name of the link entity + '_id' is converted into java by provided name stripped from the 'Id' particule.
  • primary key strategy:
    • Based on auto increment pk when not natural.
JPA2 metamodel
  • each entity is associated to a metamodel java file to build type safe criteria queries.
persistence.xml: 2 are generated.
MinuteProject artefacts are designed to be tested and ready to be deployed!
  • in src/main/resources/META-INF
    • with reference to a JTA datasource
  • in src/test/resources/META-INF
    • with reference to an embedded Connection pool
Global convention
All artefacts have an updatable nature, meaning that you can change the code or add new code and consecutive generation will keep your modifications.

Code

Translation key
/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : DomainEntityJPA2Annotation
 * - file name : DomainEntityJPA2Annotation.vm
*/
package net.sf.mp.demo.tranxy.domain.translation;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
import java.sql.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

import java.io.Serializable;
import javax.persistence.*;
import net.sf.mp.demo.tranxy.domain.tranxy.Traduction;

/**
 *
 * <p>Title: TranslationKey</p>
 *
 * <p>Description: Domain Object describing a TranslationKey entity</p>
 *
 */
@Entity (name="TranslationKey")
@Table (name="translation_key")
@NamedQueries({
  @NamedQuery(name="TranslationKey.findAll", query="SELECT translationKey FROM TranslationKey translationKey")
 ,@NamedQuery(name="TranslationKey.findByKeyName", query="SELECT translationKey FROM TranslationKey translationKey WHERE translationKey.keyName = :keyName")
 ,@NamedQuery(name="TranslationKey.findByKeyNameContaining", query="SELECT translationKey FROM TranslationKey translationKey WHERE translationKey.keyName like :keyName")
 ,@NamedQuery(name="TranslationKey.findByDescription", query="SELECT translationKey FROM TranslationKey translationKey WHERE translationKey.description = :description")
 ,@NamedQuery(name="TranslationKey.findByDescriptionContaining", query="SELECT translationKey FROM TranslationKey translationKey WHERE translationKey.description like :description")
})
public class TranslationKey implements Serializable {
    private static final long serialVersionUID = 1L;
 
    public static final String FIND_ALL = "TranslationKey.findAll";
    public static final String FIND_BY_KEYNAME = "TranslationKey.findByKeyName";
    public static final String FIND_BY_KEYNAME_CONTAINING ="TranslationKey.findByKeyNameContaining";
    public static final String FIND_BY_DESCRIPTION = "TranslationKey.findByDescription";
    public static final String FIND_BY_DESCRIPTION_CONTAINING ="TranslationKey.findByDescriptionContaining";
 
    @Id @Column(name="id" )
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

//MP-MANAGED-ADDED-AREA-BEGINNING @key_name-field-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @key_name-field-annotation@
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-key_name@
    @Column(name="key_name",  length=200,  nullable=true,  unique=false)
    private String keyName; 
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-ADDED-AREA-BEGINNING @description-field-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @description-field-annotation@
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-description@
    @Column(name="description",  length=400,  nullable=true,  unique=false)
    private String description; 
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @traductions-field-translation_key@
    @OneToMany (targetEntity=net.sf.mp.demo.tranxy.domain.tranxy.Traduction.class, fetch=FetchType.LAZY, mappedBy="key", cascade=CascadeType.REMOVE)//, cascade=CascadeType.ALL)
    private Set <Traduction> traductions = new HashSet<Traduction>(); 

//MP-MANAGED-UPDATABLE-ENDING
    /**
    * Default constructor
    */
    public TranslationKey() {
    }

 /**
 * All field constructor 
 */
    public TranslationKey(
       Long id,
       String keyName,
       String description) {
       //primary keys
       setId (id);
       //attributes
       setKeyName (keyName);
       setDescription (description);
       //parents
    }

 public TranslationKey flat() {
    return new TranslationKey(
          getId(),
          getKeyName(),
          getDescription()
    );
 }

    public Long getId() {
        return id;
    }
 
    public void setId (Long id) {
        this.id =  id;
    }
    
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @GETTER-SETTER-key_name@
    public String getKeyName() {
        return keyName;
    }
 
    public void setKeyName (String keyName) {
        this.keyName =  keyName;
    }    
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @GETTER-SETTER-description@
    public String getDescription() {
        return description;
    }
 
    public void setDescription (String description) {
        this.description =  description;
    }    
//MP-MANAGED-UPDATABLE-ENDING



//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @traductions-getter-translation_key@
    public Set<Traduction> getTraductions() {
        if (traductions == null){
            traductions = new HashSet<Traduction>();
        }
        return traductions;
    }

    public void setTraductions (Set<Traduction> traductions) {
        this.traductions = traductions;
    } 
    
    public void addTraductions (Traduction traduction) {
         getTraductions().add(traduction);
    }
    
//MP-MANAGED-UPDATABLE-ENDING


//MP-MANAGED-ADDED-AREA-BEGINNING @implementation@
//MP-MANAGED-ADDED-AREA-ENDING @implementation@

}
Language
/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : DomainEntityJPA2Annotation
 * - file name : DomainEntityJPA2Annotation.vm
*/
package net.sf.mp.demo.tranxy.domain.tranxy;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
import java.sql.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

import java.io.Serializable;
import javax.persistence.*;
import net.sf.mp.demo.tranxy.domain.tranxy.Traduction;

/**
 *
 * <p>Title: Language</p>
 *
 * <p>Description: Domain Object describing a Language entity</p>
 *
 */
@Entity (name="Language")
@Table (name="language")
@NamedQueries({
  @NamedQuery(name="Language.findAll", query="SELECT language FROM Language language")
 ,@NamedQuery(name="Language.findByCode", query="SELECT language FROM Language language WHERE language.code = :code")
 ,@NamedQuery(name="Language.findByCodeContaining", query="SELECT language FROM Language language WHERE language.code like :code")
})
public class Language implements Serializable {
    private static final long serialVersionUID = 1L;
 
    public static final String FIND_ALL = "Language.findAll";
    public static final String FIND_BY_CODE = "Language.findByCode";
    public static final String FIND_BY_CODE_CONTAINING ="Language.findByCodeContaining";
 
    @Id @Column(name="idlanguage" )
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer idlanguage;

//MP-MANAGED-ADDED-AREA-BEGINNING @code-field-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @code-field-annotation@
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-code@
    @Column(name="code",  length=45, nullable=false,  unique=false)
    private String code; 
//MP-MANAGED-UPDATABLE-ENDING

//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @traductions-field-language@
    @OneToMany (targetEntity=net.sf.mp.demo.tranxy.domain.tranxy.Traduction.class, fetch=FetchType.LAZY, mappedBy="language", cascade=CascadeType.REMOVE)//, cascade=CascadeType.ALL)
    private Set <Traduction> traductions = new HashSet<Traduction>(); 

//MP-MANAGED-UPDATABLE-ENDING
    /**
    * Default constructor
    */
    public Language() {
    }

 /**
 * All field constructor 
 */
    public Language(
       Integer idlanguage,
       String code) {
       //primary keys
       setIdlanguage (idlanguage);
       //attributes
       setCode (code);
       //parents
    }

 public Language flat() {
    return new Language(
          getIdlanguage(),
          getCode()
    );
 }

    public Integer getIdlanguage() {
        return idlanguage;
    }
 
    public void setIdlanguage (Integer idlanguage) {
        this.idlanguage =  idlanguage;
    }
    
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @GETTER-SETTER-code@
    public String getCode() {
        return code;
    }
 
    public void setCode (String code) {
        this.code =  code;
    }    
//MP-MANAGED-UPDATABLE-ENDING



//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @traductions-getter-language@
    public Set<Traduction> getTraductions() {
        if (traductions == null){
            traductions = new HashSet<Traduction>();
        }
        return traductions;
    }

    public void setTraductions (Set<Traduction> traductions) {
        this.traductions = traductions;
    } 
    
    public void addTraductions (Traduction traduction) {
         getTraductions().add(traduction);
    }
    
//MP-MANAGED-UPDATABLE-ENDING


//MP-MANAGED-ADDED-AREA-BEGINNING @implementation@
//MP-MANAGED-ADDED-AREA-ENDING @implementation@

}
Tranduction
/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * More information on minuteproject:
 * twitter @minuteproject
 * wiki http://minuteproject.wikispaces.com 
 * blog http://minuteproject.blogspot.net
 * 
*/
/**
 * template reference : 
 * - name : DomainEntityJPA2Annotation
 * - file name : DomainEntityJPA2Annotation.vm
*/
package net.sf.mp.demo.tranxy.domain.tranxy;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
//MP-MANAGED-ADDED-AREA-ENDING @import@
import java.sql.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;

import java.io.Serializable;
import javax.persistence.*;
import net.sf.mp.demo.tranxy.domain.translation.TranslationKey;
import net.sf.mp.demo.tranxy.domain.tranxy.Language;

/**
 *
 * <p>Title: Traduction</p>
 *
 * <p>Description: Domain Object describing a Traduction entity</p>
 *
 */
@Entity (name="Traduction")
@Table (name="traduction")
@NamedQueries({
  @NamedQuery(name="Traduction.findAll", query="SELECT traduction FROM Traduction traduction")
 ,@NamedQuery(name="Traduction.findByTranslation", query="SELECT traduction FROM Traduction traduction WHERE traduction.translation = :translation")
 ,@NamedQuery(name="Traduction.findByTranslationContaining", query="SELECT traduction FROM Traduction traduction WHERE traduction.translation like :translation")
})
public class Traduction implements Serializable {
    private static final long serialVersionUID = 1L;
 
    public static final String FIND_ALL = "Traduction.findAll";
    public static final String FIND_BY_TRANSLATION = "Traduction.findByTranslation";
    public static final String FIND_BY_TRANSLATION_CONTAINING ="Traduction.findByTranslationContaining";
 
    @Id @Column(name="id" )
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

//MP-MANAGED-ADDED-AREA-BEGINNING @translation-field-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @translation-field-annotation@
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-translation@
    @Column(name="translation",  length=800,  nullable=true,  unique=false)
    private String translation; 
//MP-MANAGED-UPDATABLE-ENDING

    @ManyToOne (fetch=FetchType.LAZY , optional=false)
    @JoinColumn(name="Key_id", referencedColumnName = "id", nullable=false,  unique=false ) 
    private TranslationKey key;  

    @Column(name="Key_id",  nullable=false,  unique=false, insertable=false, updatable=false)
    private Long key_;

    @ManyToOne (fetch=FetchType.LAZY , optional=false)
    @JoinColumn(name="language_id", referencedColumnName = "idlanguage", nullable=false,  unique=false ) 
    private Language language;  

    @Column(name="language_id",  nullable=false,  unique=false, insertable=false, updatable=false)
    private Integer language_;

    /**
    * Default constructor
    */
    public Traduction() {
    }

 /**
 * All field constructor 
 */
    public Traduction(
       Long id,
       String translation,
       Integer language,
       Long key) {
       //primary keys
       setId (id);
       //attributes
       setTranslation (translation);
       //parents
       this.key = new TranslationKey();
       this.key.setId(key); //ID
       this.language = new Language();
       this.language.setIdlanguage(language); //IDLANGUAGE
    }

 public Traduction flat() {
    return new Traduction(
          getId(),
          getTranslation(),
          getLanguage_(),
          getKey_()
    );
 }

    public Long getId() {
        return id;
    }
 
    public void setId (Long id) {
        this.id =  id;
    }
    
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @GETTER-SETTER-translation@
    public String getTranslation() {
        return translation;
    }
 
    public void setTranslation (String translation) {
        this.translation =  translation;
    }    
//MP-MANAGED-UPDATABLE-ENDING


    public TranslationKey getKey () {
     return key;
    }
 
    public void setKey (TranslationKey key) {
     this.key = key;
    }

    public Long getKey_() {
        return key_;
    }
 
    public void setKey_ (Long key) {
        this.key_ =  key;
    }
 
    public Language getLanguage () {
     return language;
    }
 
    public void setLanguage (Language language) {
     this.language = language;
    }

    public Integer getLanguage_() {
        return language_;
    }
 
    public void setLanguage_ (Integer language) {
        this.language_ =  language;
    }

//MP-MANAGED-ADDED-AREA-BEGINNING @implementation@
//MP-MANAGED-ADDED-AREA-ENDING @implementation@

}
persistence.xml in test directory
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
<!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @PERSISTENCE-UNIT-tranxy@-->
    <persistence-unit name="tranxy" transaction-type="RESOURCE_LOCAL">
<!--MP-MANAGED-UPDATABLE-ENDING-->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <!-- tranxy --> 
        <class>net.sf.mp.demo.tranxy.domain.tranxy.Language</class>
        <class>net.sf.mp.demo.tranxy.domain.tranxy.Traduction</class>
        <!-- translation --> 
        <class>net.sf.mp.demo.tranxy.domain.translation.TranslationKey</class>
        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver" />
            <property name="hibernate.connection.url" value="jdbc:mysql://127.0.0.1:3306/tranxy" />
            <property name="hibernate.connection.username" value="root" />
            <property name="hibernate.connection.password" value="mysql" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
        </properties> 
    </persistence-unit>
</persistence>

Persistence.xml in main directory

The persistence.xml provides a configuration with embedded connection pool.
If the user want to use a remote connection pool accessed by JNDI, the user has to put property

lt;property name="environment" value="remote" />
Under the target JPA2 node.

Alter Generated Code and Unit Test

With Minuteproject one shot-generation as 'too-much-often' seen is over!
Be ready for continuous-refactoring of your backend!

Add a validation annotation

In Language class
//MP-MANAGED-ADDED-AREA-BEGINNING @import@
import javax.validation.constraints.*;
//MP-MANAGED-ADDED-AREA-ENDING @import@

...
//MP-MANAGED-ADDED-AREA-BEGINNING @code-field-annotation@
    @Size(min = 2)
//MP-MANAGED-ADDED-AREA-ENDING @code-field-annotation@
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ATTRIBUTE-code@
    @Column(name="code",  length=45, nullable=false,  unique=false)
    private String code; 

Add the imports between the MP-MANAGED-ADDED-AREA-BEGINNING @import@ and MP-MANAGED-ADDED-AREA-ENDING @import@ comments
Add the annotation between MP-MANAGED-ADDED-AREA-BEGINNING @xxxx-field-annotation@ and MP-MANAGED-ADDED-AREA-ENDING @xxxx-field-annotation@ comments

Now further generation will keep your added code.

Unit test

In src/test/java add the TranxyTest class in package mytest
The validation scenario has been inspired by this link.

package mytest;

import javax.persistence.*;
import javax.validation.*;
import javax.validation.constraints.*;

import static junit.framework.Assert.*;

import org.junit.*;

import net.sf.mp.demo.tranxy.domain.tranxy.*;

public class TranxyTest {

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("tranxy");
 EntityManager em = emf.createEntityManager();
 
 @Test
 public void testLanguage() {
  EntityTransaction tx = em.getTransaction(); 
  tx.begin();
  Language language = new Language();
  language.setCode("FR");
  em.persist(language);
  tx.commit();
 }
 
    @Test
    public void testTooSmallLanguage() {

        try {
      EntityTransaction tx = em.getTransaction(); 
      tx.begin();
      Language language = new Language();
      language.setCode("F");
      em.persist(language);
            fail("Expected ConstraintViolationException wasn't thrown.");
            tx.commit();
        } 
        catch (ConstraintViolationException e) {
            assertEquals(1, e.getConstraintViolations().size());
            ConstraintViolation violation = 
                e.getConstraintViolations().iterator().next();
            assertEquals("code", violation.getPropertyPath().toString());
            assertEquals(
                Size.class, 
                violation.getConstraintDescriptor().getAnnotation().annotationType());
        }
    } 
 
 @Before
 public void clean () {
  EntityTransaction tx = em.getTransaction(); 
  tx.begin();
  Query q = em.createQuery("delete Language");
  q.executeUpdate();
  tx.commit();
 }
}


Execute with
>mvn clean package
The 2 tests pass.

Download


The result can be downloaded on google code minuteproject.

No comments:

Post a Comment