<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="javax.persistence.schema-generation.database.action" value="${javax.persistence.schema-generation.database.action}"/> </properties> </persistence-unit> </persistence>
Building environment specific artifacts with classifier
TweetPosted on Friday Mar 20, 2015 at 03:09PM in Maven
Consider following multi-module Maven project:
-
classifier
: The parent & aggregator project -
persistence
: A jar project which holds JPA entities and a persistence descriptor (persistence.xml
) -
web
: A war project which depends onpersistence
project
persistence
project contains following persistence descriptor:
I need to set javax.persistence.schema-generation.database.action
property as drop-and-create
for development environment, but none
for production environment. in such case, using profiles and filtering might be a solution, but its shortcoming is that we can hold only one (among environment specific builds) artifact in the local repository because these builds has same coordinate. it may bring unexpected result such as deploying development build to the production environment by some accident. in such case, using classifier would be a better solution.
Preparation
First, let’s enable resource filtering in persistence
project.
<build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <!-- Filter and copy resources under src/main/resources into target/classes (default location) --> <execution> <id>default-resources</id> <phase>process-resources</phase> <goals> <goal>resources</goal> </goals> <configuration> <filters> <filter>${basedir}/filters/dev.properties</filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build>
Then put filters/dev.properties
:
javax.persistence.schema-generation.database.action=drop-and-create
Set a dependency in web
project:
<dependencies> <dependency> <groupId>org.nailedtothex.examples.classifier</groupId> <artifactId>persistence</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
Add configurations for producing artifacts for production
Now we can make artifacts that holds filtered persistence.xml
for development environment. next, let’s add configurations for producing artifacts for production environment with prod
classifier.
Put following profile definition into persistence
project to make the project to produce both of development and production (with prod
classifier) artifacts:
<profile> <id>prod</id> <properties> <filteredResources>target/filtered-classes</filteredResources> </properties> <build> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <!-- Filter and copy resources under src/main/resources into target/filtered-classes/prod --> <execution> <id>prod-resources</id> <phase>process-resources</phase> <goals> <goal>resources</goal> </goals> <configuration> <outputDirectory>${filteredResources}/prod</outputDirectory> <filters> <filter>${basedir}/filters/prod.properties</filter> </filters> </configuration> </execution> <!-- Copy classes under target/classes into target/filtered-classes/prod --> <!-- Existing files will not be overwritten. --> <!-- see http://maven.apache.org/plugins/maven-resources-plugin/resources-mojo.html#overwrite --> <execution> <id>copy-classes-prod</id> <phase>process-classes</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${filteredResources}/prod</outputDirectory> <resources> <resource> <directory>${project.build.outputDirectory}</directory> <filtering>false</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <!-- Create the production jar with files inside target/filtered-classes/prod --> <execution> <id>prod-jar</id> <phase>package</phase> <goals> <goal>jar</goal> </goals> <configuration> <classifier>prod</classifier> <classesDirectory>${filteredResources}/prod</classesDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile>
Also put filters/prod.properties
:
javax.persistence.schema-generation.database.action=none
Issue following command:
$ mvn clean install -P prod
Result:
... [INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ persistence --- [INFO] Building jar: /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT.jar [INFO] [INFO] --- maven-jar-plugin:2.6:jar (prod-jar) @ persistence --- [INFO] Building jar: /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT-prod.jar [INFO] [INFO] --- maven-install-plugin:2.4:install (default-install) @ persistence --- [INFO] Installing /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT.jar to /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT.jar [INFO] Installing /Users/kyle/src/classifier/persistence/pom.xml to /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT.pom [INFO] Installing /Users/kyle/src/classifier/persistence/target/persistence-1.0-SNAPSHOT-prod.jar to /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT-prod.jar ...
You can see both of artifacts are installed as expected:
$ unzip -p /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT.jar META-INF/persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> </properties> </persistence-unit> </persistence> $ unzip -p /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/persistence/1.0-SNAPSHOT/persistence-1.0-SNAPSHOT-prod.jar META-INF/persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="myPU"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <property name="javax.persistence.schema-generation.database.action" value="none"/> </properties> </persistence-unit> </persistence>
So what is needed for web
project? put following profile as well:
<profile> <id>prod</id> <dependencies> <dependency> <groupId>org.nailedtothex.examples.classifier</groupId> <artifactId>persistence</artifactId> <version>1.0-SNAPSHOT</version> <classifier>prod</classifier> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <executions> <execution> <id>default-war</id> <phase>package</phase> <goals> <goal>war</goal> </goals> <configuration> <packagingExcludes>WEB-INF/lib/persistence-1.0-SNAPSHOT-prod.jar</packagingExcludes> </configuration> </execution> <execution> <id>prod-war</id> <phase>package</phase> <goals> <goal>war</goal> </goals> <configuration> <classifier>prod</classifier> <packagingExcludes>WEB-INF/lib/persistence-1.0-SNAPSHOT.jar</packagingExcludes> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile>
Then you will get both of artifacts installed after issuing mvn clean install -P prod
as follows:
$ unzip -l /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/web/1.0-SNAPSHOT/web-1.0-SNAPSHOT.war | grep persistence 3521 03-20-15 14:25 WEB-INF/lib/persistence-1.0-SNAPSHOT.jar $ unzip -l /Users/kyle/.m2/repository/org/nailedtothex/examples/classifier/web/1.0-SNAPSHOT/web-1.0-SNAPSHOT-prod.war | grep persistence 3513 03-20-15 14:25 WEB-INF/lib/persistence-1.0-SNAPSHOT-prod.jar
Arquillian EJB-JAR/EAR testing examples
TweetPosted on Friday Mar 20, 2015 at 10:33AM in Arquillian
There are plenty of examples of Arquillian testing with WAR deployments, but not for other deployments such as EJB-JAR or EAR. so I created some examples. these examples were tested against Arquillian 1.1.7.Final, using WildFly 8.2.0.Final as remote container. the entire project can be obtained from GitHub.
Testing against EJB-JAR deployment
Assume we have a simple EJB in a EJB-JAR project as follows:
@Stateless @LocalBean public class SomeEjb { public String hello(String name) { return "Hello, " + name; } }
Test class:
@RunWith(Arquillian.class) public class EjbJarIT { @Deployment public static Archive<?> createDeploymentPackage() { final Archive archive = ShrinkWrap.create(JavaArchive.class).addClass(SomeEjb.class); return archive; } @EJB private SomeEjb someEjb; @Test public void test() { Assert.assertEquals("Hello, Kyle", someEjb.hello("Kyle")); } }
The deployment will be a WAR through Arquillian’s automatic enrichment process while the method annotated as @Deployment
produced JavaArchive
.
Testing against EAR deployment
Assume we have a simple EAR project which depends on the preceding EJB-JAR project.
Test class:
@RunWith(Arquillian.class) public class EarIT { @Deployment public static Archive<?> createDeploymentPackage() throws IOException { final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "ejb-jar.jar").addClass(SomeEjb.class); // Embedding war package which contains the test class is needed // So that Arquillian can invoke test class through its servlet test runner final WebArchive testWar = ShrinkWrap.create(WebArchive.class, "test.war").addClass(EarIT.class); final EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class) .setApplicationXML("test-application.xml") .addAsModule(ejbJar) .addAsModule(testWar); return ear; } @EJB private SomeEjb someEjb; @Test public void test() { Assert.assertEquals("Hello, Kyle", someEjb.hello("Kyle")); } }
test-application.xml
which will be embed as application.xml
:
<application> <display-name>ear</display-name> <module> <ejb>ejb-jar.jar</ejb> </module> <module> <web> <web-uri>test.war</web-uri> <context-root>/test</context-root> </web> </module> </application>
Also I have an another example that uses the EAR which Maven has produced because creating EAR with ShrinkWrap would be annoying in some complex cases. the @Deployment
method will embed the test WAR into the EAR, and add a module
element into existing application.xml
before returning the archive to Arquillian runtime. the @Deployment
method would be something like this:
... @Deployment public static Archive<?> createDeploymentPackage() throws IOException { final String testWarName = "test.war"; final EnterpriseArchive ear = ShrinkWrap.createFromZipFile( EnterpriseArchive.class, new File("target/ear-1.0-SNAPSHOT.ear")); addTestWar(ear, EarFromZipFileIT.class, testWarName); ...
Tags: arquillian ear ejb
Arquillian Persistence Extension examples
TweetPosted on Wednesday Mar 18, 2015 at 05:47PM in Arquillian
The whole project can be obtained from GitHub. tested with WildFly 8.2.0.Final as remote container.
Implementation (test target)
Assume we have very simple 2 entities as follows:
@Entity public class Dept implements Serializable { @Id private Integer id; @Column(nullable = false) private String name; @OneToMany(mappedBy = "dept") private Collection<Employee> employees; ... @Entity public class Employee implements Serializable { @Id private Integer id; @Column(nullable = false) private String name; @JoinColumn(nullable = false) @ManyToOne private Dept dept; ...
Test target EJB:
@Stateless @LocalBean public class HumanResourcesBean { @PersistenceContext private EntityManager em; public void addEmployee(Employee employee, Integer deptId) { final Dept dept = em.find(Dept.class, deptId); dept.getEmployees().add(employee); employee.setDept(dept); em.persist(employee); } public void addDept(Dept dept, Employee employee) { Collection<Employee> employees = new ArrayList<>(); dept.setEmployees(employees); employees.add(employee); employee.setDept(dept); em.persist(dept); em.persist(employee); } }
addEmployee() testing
Test method of addEmployee():
@Test @UsingDataSet("input.xml") @ShouldMatchDataSet(value = "addEmployee-expected.xml", orderBy = "id") public void addEmployeeTest() throws Exception { Employee emp = new Employee(); emp.setId(2002); emp.setName("Todd"); humanResourcesBean.addEmployee(emp, 200); }
Initial entry data (input.xml):
<dataset> <Dept id="100" name="Sales"/> <Dept id="200" name="Finance"/> <Employee id="1000" name="Scott" dept_id="100"/> <Employee id="1001" name="Martin" dept_id="100"/> <Employee id="1002" name="Nick" dept_id="100"/> <Employee id="2000" name="Jordan" dept_id="200"/> <Employee id="2001" name="David" dept_id="200"/> </dataset>
Expected data (addEmployee-expected.xml):
<dataset> <Employee id="1000" name="Scott" dept_id="100"/> <Employee id="1001" name="Martin" dept_id="100"/> <Employee id="1002" name="Nick" dept_id="100"/> <Employee id="2000" name="Jordan" dept_id="200"/> <Employee id="2001" name="David" dept_id="200"/> <Employee id="2002" name="Todd" dept_id="200"/> <!-- Newly added --> </dataset>
addDept() testing
Test method of addDept():
@Test @UsingDataSet("input.xml") @ShouldMatchDataSet(value = "addDept-expected.xml", orderBy = "id") public void addDeptTest() throws Exception { Dept dept = new Dept(); dept.setId(300); dept.setName("Engineering"); Employee emp = new Employee(); emp.setId(3000); emp.setName("Carl"); humanResourcesBean.addDept(dept, emp); }
Initial entry data (input.xml) is the same to previous testing.
Expected data (addDept-expected.xml):
<dataset> <Dept id="100" name="Sales"/> <Dept id="200" name="Finance"/> <Dept id="300" name="Engineering"/> <!-- Newly added --> <Employee id="1000" name="Scott" dept_id="100"/> <Employee id="1001" name="Martin" dept_id="100"/> <Employee id="1002" name="Nick" dept_id="100"/> <Employee id="2000" name="Jordan" dept_id="200"/> <Employee id="2001" name="David" dept_id="200"/> <Employee id="3000" name="Carl" dept_id="300"/> <!-- Newly added --> </dataset>
It works well with multiple tables.
addDept() testing with DBUnit
Sometimes use of DBUnit directly is useful for complex assertion. in such case you need to care following conditions:
-
If you use JPA, force EntityManager to execute DMLs via invoking
em.flush()
before assertion -
Include test data to the Arquillian’s application archive so that DBUnit can load these data on the server side
The XML can be included via addAsResource()
method as follows:
@Deployment public static Archive<?> createDeploymentPackage() { final WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "test.war") .addPackage(Dept.class.getPackage()) .addClass(HumanResourcesBean.class) .addAsResource("datasets/addDept-expected.xml") // to be loaded by DBUnit on the server side .addAsResource("test-persistence.xml", "META-INF/persistence.xml"); // System.out.println(webArchive.toString(true)); return webArchive; }
The test method of addDept() and related convenient methods:
@Test @UsingDataSet("input.xml") public void addDeptTestWithDbUnit() throws Exception { Dept dept = new Dept(); dept.setId(300); dept.setName("Engineering"); Employee emp = new Employee(); emp.setId(3000); emp.setName("Carl"); humanResourcesBean.addDept(dept, emp); em.flush(); // force JPA to execute DMLs before assertion final IDataSet expectedDataSet = getDataSet("/datasets/addDept-expected.xml"); assertTable(expectedDataSet.getTable("Dept"), "select * from dept order by id"); assertTable(expectedDataSet.getTable("Employee"), "select * from employee order by id"); } private static IDataSet getDataSet(String path) throws DataSetException { return new FlatXmlDataSetBuilder().build(HumanResourcesBeanIT.class.getResource(path)); } private void assertTable(ITable expectedTable, String sql) throws SQLException, DatabaseUnitException { try (Connection cn = ds.getConnection()) { IDatabaseConnection icn = null; try { icn = new DatabaseConnection(cn); final ITable queryTable = icn.createQueryTable(expectedTable.getTableMetaData().getTableName(), sql); Assertion.assertEquals(expectedTable, queryTable); } finally { if (icn != null) { icn.close(); } } } }
Disabling color escape sequences in WildFly's console logging for IDE
TweetPosted on Wednesday Mar 18, 2015 at 11:31AM in WildFly
I’m using IntelliJ IDEA for developing Java EE applications on WildFly. its built-in WildFly console appears as follows:
... [0m11:20:28,608 INFO [org.jboss.as.server] (Controller Boot Thread) JBAS015888: Creating http management service using socket-binding (management-http) [0m[0m11:20:28,625 INFO [org.xnio] (MSC service thread 1-9) XNIO version 3.3.0.Final [0m[0m11:20:28,631 INFO [org.xnio.nio] (MSC service thread 1-9) XNIO NIO Implementation Version 3.3.0.Final ...
You can see strange characters in the head of every lines. they are color escape sequences that works fine with terminal emulators but not for IntelliJ IDEA’s console output. to disable color escape sequences, issue following command in jboss-cli
:
/subsystem=logging/console-handler=CONSOLE:write-attribute(name=named-formatter, value=PATTERN)
Now strange characters disappeared from IntelliJ IDEA’s console as follows:
... 2015-03-18 11:26:11,800 INFO [org.jboss.as.server] (Controller Boot Thread) JBAS015888: Creating http management service using socket-binding (management-http) 2015-03-18 11:26:11,812 INFO [org.xnio] (MSC service thread 1-4) XNIO version 3.3.0.Final 2015-03-18 11:26:11,817 INFO [org.xnio.nio] (MSC service thread 1-4) XNIO NIO Implementation Version 3.3.0.Final ...
Using JPA 2.1 AttributeConverter against Java8 LocalDate / LocalDateTime
TweetPosted on Tuesday Mar 17, 2015 at 01:50PM in JPA
I created an example project using https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa which ran on WildFly 8.2.0.Final (Hibernate 4.3.7) and H2 / Apache Derby database.
the whole project can be obtained from https://github.com/lbtc-xxx/jpa21converter .
You don’t need to define any additional configuration in persistence.xml
if you use converters in EE environment. it goes like this:
The converter for LocalDate between DATE
@Converter(autoApply = true) public class MyLocalDateConverter implements AttributeConverter<java.time.LocalDate, java.sql.Date> { @Override public java.sql.Date convertToDatabaseColumn(java.time.LocalDate attribute) { return attribute == null ? null : java.sql.Date.valueOf(attribute); } @Override public java.time.LocalDate convertToEntityAttribute(java.sql.Date dbData) { return dbData == null ? null : dbData.toLocalDate(); } }
The converter for LocalDateTime between TIMESTAMP
@Converter(autoApply = true) public class MyLocalDateTimeConverter implements AttributeConverter<java.time.LocalDateTime, java.sql.Timestamp> { @Override public java.sql.Timestamp convertToDatabaseColumn(java.time.LocalDateTime attribute) { return attribute == null ? null : java.sql.Timestamp.valueOf(attribute); } @Override public java.time.LocalDateTime convertToEntityAttribute(java.sql.Timestamp dbData) { return dbData == null ? null : dbData.toLocalDateTime(); } }
Entity class
@Entity public class MySimpleTable implements Serializable { @Id @GeneratedValue private Long id; private java.time.LocalDateTime someLocalDateTime; private java.time.LocalDate someLocalDate; ...
Hibernate produces the DDL against H2 as follows:
create table MySimpleTable ( id bigint not null, someLocalDate date, someLocalDateTime timestamp, primary key (id) )
Using converters with @EmbeddedId
Converters doesn’t work with fields that annotated as @Id
(see http://stackoverflow.com/questions/28337798/hibernate-fails-to-load-jpa-2-1-converter-when-loaded-with-spring-boot-and-sprin ) but works with @EmbeddedId
class.
Entity class:
@Entity public class MyCompositeKeyTable implements Serializable { @EmbeddedId private MyCompositeKeyEmbeddable key; ...
Embeddable class:
@Embeddable public class MyCompositeKeyEmbeddable implements Serializable { @Column(nullable = false) private java.time.LocalDateTime someLocalDateTime; @Column(nullable = false) private java.time.LocalDate someLocalDate; ...
Produced DDL:
create table MyCompositeKeyTable ( someLocalDate date not null, someLocalDateTime timestamp not null, primary key (someLocalDate, someLocalDateTime) )