@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; ...
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:
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) )
An example of Maven EAR project consists of an EJB interface, an EJB implementation and a WAR
TweetPosted on Friday Mar 06, 2015 at 10:43PM in Maven
The project consists of following principal modules:
-
eartest-ejb-api: holds an EJB local interface named
Hello
. packaging=jar. no dependency. -
eartest-ejb-impl: holds an EJB implementation named
HelloImpl
which implementsHello
. packaging=ejb. depends on eartest-ejb-api. -
eartest-war: holds an Servlet which has an injection point of
Hello
interface. depends on eartest-ejb-api. -
eartest-ear: holds above 3 modules in the EAR.
Whole project is can be obtained from https://github.com/lbtc-xxx/eartest .
Structure of eartest-ear module
$ tree eartest-ear/target/eartest-ear eartest-ear/target/eartest-ear |-- META-INF | `-- application.xml |-- eartest-ejb-impl-1.0-SNAPSHOT.jar |-- eartest-war-1.0-SNAPSHOT.war `-- lib `-- eartest-ejb-api-1.0-SNAPSHOT.jar 2 directories, 4 files
Structure of eartest-war module
$ tree eartest-war/target/eartest-war eartest-war/target/eartest-war |-- META-INF `-- WEB-INF `-- classes `-- eartest `-- war `-- MyServlet.class 5 directories, 1 file
MyServlet can reference eartest-ejb-api-1.0-SNAPSHOT.jar
because it’s placed under lib
directory in the parent EAR. this packaging style is called as Skinny WAR.
Structure of eartest-ejb-api
$ tree eartest-ejb-api/target/classes eartest-ejb-api/target/classes `-- eartest `-- ejb `-- api `-- Hello.class 3 directories, 1 file
Structure of eartest-ejb-impl
$ tree eartest-ejb-impl/target/classes eartest-ejb-impl/target/classes |-- META-INF | `-- ejb-jar.xml `-- eartest `-- ejb `-- impl `-- HelloImpl.class 4 directories, 2 files
A problem with IntelliJ IDEA
IntelliJ has an annoying issue: Maven support cannot handle skinny wars for EAR deployments : IDEA-97324. this brings unnecessary eartest-ejb-api into WEB-INF/lib
inside the WAR and brings following exception. to avoid this, I need to put <scope>provided</scope>
in dependency declaration for eartest-ejb-api
in pom.xml
of eartest-war
.
Caused by: java.lang.IllegalStateException: JBAS011048: Failed to construct component instance at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:162) at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:133) at org.jboss.as.ee.component.BasicComponent.createInstance(BasicComponent.java:89) at org.jboss.as.ee.component.ComponentRegistry$ComponentManagedReferenceFactory.getReference(ComponentRegistry.java:149) at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$5.createInstance(UndertowDeploymentInfoService.java:1233) at io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start(ManagedServlet.java:215) [undertow-servlet-1.1.0.Final.jar:1.1.0.Final] ... 27 more Caused by: java.lang.IllegalArgumentException: Can not set eartest.ejb.api.Hello field eartest.war.MyServlet.hello to eartest.ejb.api.Hello$$$view17 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) [rt.jar:1.8.0_20] at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) [rt.jar:1.8.0_20] at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) [rt.jar:1.8.0_20] at java.lang.reflect.Field.set(Field.java:758) [rt.jar:1.8.0_20] at org.jboss.as.ee.component.ManagedReferenceFieldInjectionInterceptorFactory$ManagedReferenceFieldInjectionInterceptor.processInvocation(ManagedReferenceFieldInjectionInterceptorFactory.java:108) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309) at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309) at org.jboss.as.ee.component.AroundConstructInterceptorFactory$1.processInvocation(AroundConstructInterceptorFactory.java:28) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309) at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-8.2.0.Final.jar:8.2.0.Final] at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309) at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309) at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326) at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309) at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:160) ... 32 more
Testing a JBatch job using Arquillian on remote WildFly
TweetPosted on Thursday Mar 05, 2015 at 05:14PM in JBatch
I pushed entire project to https://github.com/lbtc-xxx/arquillian-jbatch .
While I prefer remote EJB way like my previous posting for JBatch testing, it works well for simple project. but little slower than remote EJB on my environment.
Tags: arquillian jbatch wildfly