1. 2015-10-20 - Test depths within Java EE; Tags: Test depths within Java EE
    Loading...

    Test depths within Java EE

    TDD and BDD is a crucial discipline to write good and robust applications. Testing within the Java EE may cover several test depths. This post is only a short overview of possible involved products.

    Testing - test depth Local Testing

    • In the local testing part or Java SE Testing, we test against a single class.
    • Therefore the test execution is fast.
    • Preferred tools are JUnit (or TestNG), Mocking frameworks like Mockito

    Multi-Unit Testing

    • This test stage test against a service or a dedicated environment like CDI provider or JPA DB
    • For CDI tests: CDI-Unit, Apache DeltaSpike
    • Tests in CDI involves correct setup and wiring
    • For JPA tests: Testing against in-memory databases
    • Tests in JPA involves proper setup and logical queries correctness
    • since tests are executed against an environment, they need more time to be executed

    Integration Testing

    • In this test stage, you may test the component, subsystem or the whole application
    • Arquilian allows in-container testing with JBoss and other Java EE vendors
    • Apache OpenEJB can be used to start test against the whole Java EE Stack
    • Since you are testing against a defined target environment, it takes more time to test.
  2. 2015-10-17 - Oracle DB Datatype for boolean - which to choose for Java Persistence?; Tags: Oracle DB Datatype for boolean - which to choose for Java Persistence?
    Loading...

    Oracle DB Datatype for boolean - which to choose for Java Persistence?

    If you have to deal with the Oracle DB (11g), Boolean values have no specific datatype yet. Some uses number - a SMALLINT, some uses a character - VARCHAR(1). Number or Character - which to choose? This post illustrates both approaches for the Oracle DB for Java with the major Persistence APIs JDBC and JPA.

    JDBC

    The Java Database Connectivity (JDBC) API is the industry standard for database-independent connectivity between the Java programming language and a wide range of databases SQL databases ..

    In the interface java.sql.ResultSet.getBoolean(..) method, we can find following javadoc:

    If the designated column has a datatype of CHAR or VARCHAR and contains a "0" or has a datatype of BIT, TINYINT, SMALLINT, INTEGER or BIGINT and contains a 0, a value of false is returned. If the designated column has a datatype of CHAR or VARCHAR and contains a "1" or has a datatype of BIT, TINYINT, SMALLINT, INTEGER or BIGINT and contains a 1, a value of true is returned.

    It seems numeric values (even stored as character) are the preferred way. Please consider, don’t mix things up. Unix or Linux has a exit code 0. A successful command returns a 0. Any other non-zero value can usually be interpreted as error code. What we can say for sure for Boolean values within the JDBC/JPA:

    • 0 ⇒ false
    • 1 ⇒ true

    JPA

    The Java Persistence API is the Java API for the management of persistence and object/relational mapping in Java EE and Java SE environments. It provides an object/relational mapping facility for the Java application developer using a Java domain model to manage a relational database.

    JSR-317, JSR-338

    Number Approach

    Finding the article Using the Java Persistence API, for the automatic schema generation Oracle will use for Boolean data types the db type NUMBER(1). The JPA (implementations) will set the correct value for true and false then. A small example

    @Entity
    public class CreditCard {
        /**
         * Primary Account Number
         */
        @Id
        private String pan;
        private Integer sequenceNumber = 0;
        /**
         * flag if card is on the blacklist
         */
        @Basic
        private boolean blacklisted;
        //some auto-generated getters and setters ..
    }
    

    The JPA will take for the Boolean property blacklisted a number datatype for the respective database. A small JUnit Test

    public class CreditCardBooleanTest {
        private EntityManager em;
        @Before
        public void setUp() throws Exception {
            EntityManagerFactory factory = Persistence.createEntityManagerFactory("h2mem");
            em = factory.createEntityManager();
            CreditCard masterCard = new CreditCard();
            masterCard.setPan("MA-PAN-4711");
            masterCard.setBlacklisted(false);
            CreditCard visa = new CreditCard();
            visa.setPan("VISA-PAN-4711");
            visa.setBlacklisted(true);
            em.getTransaction().begin();
            em.persist(masterCard);
            em.persist(visa);
            em.getTransaction().commit();
        }
        @After
        public void tearDown() throws Exception {
            if (em.isOpen()) {
                em.close();
            }
        }
        @Test
        public void testBooleanFlag() {
            // card is not blacklisted = false
            CreditCard creditCard = em.find(CreditCard.class, "MA-PAN-4711");
            assertFalse("Mastercard is not blacklisted", creditCard.isBlacklisted());
            // String jpql = "SELECT c FROM CreditCard c WHERE c.blacklisted = false";
            // does also work, false is 0
            String jpql = "SELECT c FROM CreditCard c WHERE c.blacklisted = 0";
            TypedQuery<CreditCard> query = em.createQuery(jpql, CreditCard.class);
            CreditCard creditCard2 = query.getSingleResult();
            assertEquals("same PAN", creditCard.getPan(), creditCard2.getPan());
            // card is blacklisted = true
            creditCard = em.find(CreditCard.class, "VISA-PAN-4711");
            assertTrue("Visa is blacklisted", creditCard.isBlacklisted());
            // jpql = "SELECT c FROM CreditCard c WHERE c.blacklisted = true";
            // does also work, true is 1
            jpql = "SELECT c FROM CreditCard c WHERE c.blacklisted = 1";
            query = em.createQuery(jpql, CreditCard.class);
            creditCard2 = query.getSingleResult();
            assertEquals("same PAN", creditCard.getPan(), creditCard2.getPan());
        }
    }
    
    • The JUnit test runs against the in-memory H2 database
    • The JPA objects, i.e. DDL is automatically generated by the JPA
    • You can use the boolean values true and false in the JPQL
    • You can also use the numeric values 1 and 0 in the JPQL
    • As datatype a SMALLINT was taken for the boolean value
    • Against the Oracle DB NUMBER(1) is used, you might optimize the datatype by using SMALLINT

    Character Approach

    Compared to Number a single char takes less disk space. Many thanks to Christian Gohmann for this insight.

    [sql] SQL> SELECT dump(1, 10) from dual; DUMP(1,10) ------------------ Typ=2 Len=2: 193,2 [/sql]
    NUMBER ⇒ SMALLINT, 2 Byte
    [sql] SQL> SELECT dump('Y', 10) from dual; DUMP('Y',10) ---------------- Typ=96 Len=1: 89 [/sql]
    VARCHAR2(1) ⇒ 1 Byte, use with Check Constraint ('Y' or 'N')

    The check constraint avoids any illegal values to be inserted.

    Custom Hibernate Mapping

    Hibernate supports with its Hibernate annotations the mapping to the characters ‘Y’ and ‘N’. Keep in mind, this is a non JPA feature! Add the Maven dependency to your persistence pom.xml to use this feature.

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-annotations</artifactId>
        <version>3.5.6-Final</version>
    </dependency>
    

    To map boolean to char use org.hibernate.annotations.Type of "yes_no"

    @Entity
    public class Offer {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String details;
        @Type(type = "yes_no")
        private boolean accepted;
    }
    

    A small JUnit test

    public class OfferBooleanTest {
        private EntityManager em;
        @Before
        public void setUp() throws Exception {
            EntityManagerFactory factory = Persistence.createEntityManagerFactory("h2mem");
            em = factory.createEntityManager();
            Offer offer = new Offer();
            offer.setAccepted(true);
            offer.setDetails("test offer");
            Offer refusedOffer = new Offer();
            refusedOffer.setDetails("example refused offer");
            em.getTransaction().begin();
            em.persist(offer);
            em.persist(refusedOffer);
            em.getTransaction().commit();
        }
        @After
        public void tearDown() throws Exception {
            if (em.isOpen()) {
                em.close();
            }
        }
        @Test
        public void testBooleanString() {
            String jpql = "SELECT o FROM Offer o WHERE o.accepted='Y'";
            TypedQuery<Offer> query = em.createQuery(jpql, Offer.class);
            Offer wanted = query.getSingleResult();
            assertTrue("offer was accepted", wanted.isAccepted());
            jpql = "SELECT o FROM Offer o WHERE o.accepted=false";
            wanted = em.createQuery(jpql, Offer.class).getSingleResult();
            assertFalse("refused offer found", wanted.isAccepted());
        }
    }
    
    • You can use the boolean values
    • You can use the char literals ‘Y’ and ‘N’

    A screenshot from the SQL result panel of IntelliJ intellij-boolean-as-chars

    EclipseLink JPA

    EclipseLink has no special feature of that kind, but since JPA 2.1, Converters can perform the task. See also JPA Basic Attribute Converters.

    Alternatives

    Another workaround is to store the String/character and apply the logic in a transient field/property. JPA will not store this entity property. This approach violates some design principles like Single Responsibility, etc. but should be mentioned for completeness.

    // boolean char value from the database
    private String acceptance;
    private transient boolean accepted;
    ...
    public boolean isAccepted {
        return "Y".equals(acceptance);
    }
    public void setAccepted(final boolean accepted) {
        this.accepted = accepted;
        this.acceptance = accepted ? "Y" : "N";
    }
    
  3. 2015-09-14 - Constructor expressions in JPQL; Tags: Constructor expressions in JPQL
    Loading...

    Constructor expressions in JPQL

    In JPA it is possible to create directly a new object from JPQL SELECT statement, instead of fetching the result list and mapping the attributes. The JPA supports the constructor expressions for that.

    A constructor may be used in the SELECT list to return an instance of a Java class. The specified class is not required to be an entity or to be mapped to the database. The constructor name must be fully qualified.

    4.8.2 Constructor Expressions in the SELECT Clause, JSR-317 - Java Persistence 2.0, Page 162 A simple DTO (Data Transfer Object, POJO):

    public class CustomerDetails {
        private long id;
        private String name;
        public CustomerDetails(long id, String description) {
            this.id = id;
            this.name = description;
        }
    //..
    }
    

    The repository implementation:

    @Override
    public CustomerDetails getCustomerDetails(Long customerId) {
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT NEW net.cinhtau.demo.dto.CustomerDetails(c.id, c.name) ");
        sb.append("FROM Customer c ");
        sb.append("WHERE c.id = :id ");
        TypedQuery<CustomerDetails> query = em.createQuery(sb.toString(), CustomerDetails.class);
        query.setParameter("id", customerId);
        return query.getSingleResult();
    }
    

    Pay attention that desired object has to be fully qualified (see above).

    jpa
  4. 2015-09-14 - Query abstract entities; Tags: Query abstract entities
    Loading...

    Query abstract entities

    This post demonstrates a part of inheritance with JPA 2. Abstract entities (classes) can be used to query their concrete subclasses.

    An abstract class can be specified as an entity. An abstract entity differs from a concrete entity only in that it cannot be directly instantiated. An abstract entity is mapped as an entity and can be the target of queries (which will operate over and/or retrieve instances of its concrete subclasses).

    2.11.1 Abstract Entity Classes, JSR-317, Java Persistence 2.0, Page 52 The class structure: query-abstract-entity The parent class (abstract entity):

    @Entity
    @Inheritance(strategy = JOINED)
    @Table(schema = "HR", name = "EMP")
    public abstract class Employee {
      // ..
    }
    

    The subclasses:

    @Entity
    public class FullTimeEmployee extends Employee {
        private BigDecimal salary;
    }
    @Entity
    public class PartTimeEmployee extends Employee {
        private BigDecimal hourlyWage;
    }
    

    The repository query:

    public class EmployeeRepositoryImpl implements EmployeeRepository {
        //..
        @Override
        public List<? extends Employee> findAll() {
            TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e", Employee.class);
            return query.getResultList();
        }
    }
    

    The test:

    private PartTimeEmployee joe = createPartTimeEmployee();
    private FullTimeEmployee jane = createFullTimeEmployee();
    @Before
    public void setUp() throws Exception {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("h2mem");
        em = factory.createEntityManager();
        repository = new EmployeeRepositoryImpl();
        repository.setEntityManager(em);
        em.getTransaction().begin();
        em.persist(joe);
        em.persist(jane);
        em.getTransaction().commit();
    }
    @Test
    public void testFindAll() {
        //act
        List<? extends Employee> employeeList = this.repository.findAll();
        //assert
        assertEquals("found 2 employees", 2, employeeList.size());
        assertThat("Check both employess", employeeList, contains(jane, joe));
    }
    

    Check out the code from the commit revision at github.

    jpa
  5. 2015-08-07 - Analysing JPA DDL Generation in Hibernate; Tags: Analysing JPA DDL Generation in Hibernate
    Loading...

    Analysing JPA DDL Generation in Hibernate

    Using the JPA (Java Persistence API) 2.0 with Hibernate for a database integration test against a in-memory db like H2 or HSQLDB, is a good way to test the JPA ORM (object relational mapping). In the process, errors might occur depending on the database vendor. Following example illustrate a problem with Hibernate and HSQLDB.

    The output is truncated.

    13:50:55.262 [main] DEBUG org.hibernate.SQL - insert into BLACKLIST (MANDANT,..,BLOCKEDID) values (?,..,?)
    13:50:55.263 [main] WARN  o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 3403, SQLState: 22003
    13:50:55.263 [main] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - data exception: numeric value out of range;  table: BLACKLIST column: ID
    13:50:55.272 [main] WARN  Transaction - Unexpected exception from beforeCompletion; transaction will roll back
    

    The entity

    @Entity
    @Table(name="BLACKLIST")
    public class Blacklist {
    &hellip;
        @Column(nullable = false)
        private BigInteger blockedId;
    }
    

    The value of used id

    BigInteger id = BigInteger.valueOf(6710203000580400250L);
    blacklist.setBlockedId(id);
    

    Numeric value out of range seems not to be true. H2 maps BigInteger to BigInt, so HSQLDB should behave the same way?

    Activate SQL debug in logging configuration (+logback-test.xml+).

    <logger name="org.hibernate.SQL" level="DEBUG"/>
    

    The trace:

    13:50:49.228 [main] DEBUG org.hibernate.SQL - create table BLACKLIST (id bigint not null, BLOCKEDID numeric(19,2) not null, .., primary key (id))
    

    Obviously Hibernate does not take BigInt for HSQLDB, and tries to use 19 digits with 2 decimal places. By changing the mapping, we enforce a correct mapping.

    @Entity
    @Table(name="BLACKLIST")
    public class Blacklist {
    &hellip;
        @Column(nullable = false, precision = 38, scale = 0)
        private BigInteger blockedId;
    }
    
    14:02:26.744 [main] DEBUG org.hibernate.SQL - create table BLACKLIST (id bigint not null, BLOCKEDID numeric(38,0) not null, .., primary key (id))
    

    Now the value will fit into the column.

  6. 2015-07-06 - Show SQL statements in JBoss; Tags: Show SQL statements in JBoss
    Loading...

    Show SQL statements in JBoss

    Enable property in persistence.xml

    <persistence -unit name="myPU">
        <jta-data-source>java:/oracledb</jta-data-source>
    <properties>
    <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"></property>
    <property name="showSql" value="true"></property>
        </properties>
    </persistence>

    Set level debug in logback.xml or logback-test.xml.

    <logger name="org.hibernate.SQL" level="DEBUG"></logger>
    

    If you have another logging framework, you might adapt it there. Commands for the JBoss cli

    /subsystem=logging/logger=org.hibernate.SQL:add
    /subsystem=logging/logger=org.hibernate.SQL:write-attribute(name="level", value="DEBUG")
    /subsystem=logging/root-logger=ROOT:write-attribute(name="level", value="DEBUG")
    

    Steps explained:

    • Add logger for subsystem logging
    • Set (write) log level for above logger
    • Set root log level to debug (not mandatory)