Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

We had an interceptor that was written for Hibernate 3. When we went to Hibernate 4, we discovered that methods that we were used to using didn’t exist anymore. The original Hibernate 3 code looked like:

Session session = null;
MySQLMatchingRowCountInterceptor interceptor = new MySQLMatchingRowCountInterceptor();
session = ((Session) getROEntityManager().getDelegate()).getSessionFactory().openSession(interceptor);
session.beginTransaction();
interceptor.initialize(session);

Unfortunately, SessionFactory.openSession() no longer takes an interceptor.

To define an interceptor, you need to create the Session from the SessionFactory with the .withOptions() method. Once you do that, you can specify the interceptors.

Session session = null;
MySQLMatchingRowCountInterceptor interceptor = new MySQLMatchingRowCountInterceptor();
session = ((Session) getROEntityManager().getDelegate()).getSessionFactory()
                                                        .withOptions()
                                                        .interceptor(interceptor)
                                                        .openSession();
session.beginTransaction();
interceptor.initialize(session);

The Maven dependency we were using for Hibernate 4.3.11 is:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
</dependency>

October 11th, 2016

Posted In: hibernate, Java, java ninja, Javaninja

Leave a Comment

I don’t do a lot with Hibernate directly, but sometimes I do. I had seen Hibernate inheritance before, but I never had to make one. The pattern that was in place was there was a table that had common information. There was another table that had information that was implementation-specific and there were multiple implementations. My job was to add another implementation. To accomplish the writing of the data, they had a Hibernate entity for the common table. This entity was extended by an implementation-specific entity. Then they would populate the entity and save it. Effectively writing to two tables with one logical write.

The InheritanceType is JOINED. This sets it up to be joined on by other tables (e.g. extended). The base entity was defined as follows:

@Entity
@Table(name = "FundsAudit")
@Inheritance(strategy = InheritanceType.JOINED)
public class FundsAudit {

    @Id
    @Column(name = "FundTypeKey")
    private String fundTypeKey;

    //...

}

I had to add an @InheritanceType as SINGLE_TABLE. Which basically says a table per entity. I also specified @PrimaryKeyJoinColumn. The referencedColumnName is the name of the column in the inherited table. The name is the name of the column in the entity that is extending the base table. Note that you don’t see that column listed in the entity that is being extended. That table does in fact exist. This is what I came up with to extend the base entity.

@Entity
@Table(name = "paynearme_audit")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@PrimaryKeyJoinColumn(referencedColumnName = "FundTypeKey", name = "FundTypeKey")
public class PayNearMeAudit extends FundsAudit {

    //@Id  NOTE:  You don't use ID in an entity that is inherited

    @Column(name = "PayNearMe_Order_ID")
    private long payNearMeOrderIdentifier;

    //...

}

Once I have my entities defined, it is very simple to use the object. I use the entity that I created, that extends the base entity. In my code, that is all you see referenced. I have fields from both entities/tables available to me.

PayNearMeAudit payNearMeAudit = new PayNearMeAudit();
payNearMeAudit.setAffiliateId(affiliateId);
payNearMeAudit.setHandler(String.valueOf(accountNumber));
payNearMeAudit.setPayNearMeOrderIdentifier(Long.parseLong(payNearMeOrderIdentifier));
payNearMeAudit.setTransactionDateTime(new Date());
payNearMeAudit.setTransactionType(TransactionType.Deposit.toString());
payNearMeAudit.setStatus("initiated");
payNearMeAudit.setAmount(amount);
payNearMeAudit.setFundTypeKey(new IdGeneratorImpl().generateOrderId(FundingCache.get(Constants.SITE_ID)));
payNearMeAudit.setFundType(FundType.PayNearMe.toString());
payNearMeAudit.setResponse("{\"payNearMeOrderIdentifier\":\"" + payNearMeOrderIdentifier + "\"}");
payNearMeAuditDao.insert(payNearMeAudit);
payNearMeAudit = payNearMeAuditDao.findByPayNearMeOrderIdentifier(Long.parseLong(payNearMeOrderIdentifier));

I need to ensure that I specify the value of the join column, fundTypeKey. Other than that, it just works. If you are reading the code, you would never have any idea that you were doing anything out of the ordinary.

August 30th, 2016

Posted In: hibernate

Leave a Comment

I had come up with a Springframework Junit configuration for Spring Batch that worked pretty well. here. This worked pretty well, but I wanted to have the ability to have transactions to rollback my test data for test repeatability. After much tinkering, this is what I have come up with.

Spring Batch Test Maven Dependencies

I added the following dependencies to write the Spring Batch tests.

<dependency>
    <groupId>org.springframework.batch</groupId>
    <artifactId>spring-batch-test</artifactId>
    <version>${spring.batch.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

Spring Batch Test Utilities

Spring Batch provides the JobLauncherTestUtils to make it easier to test jobs. The gist of a job test class is:

JobExecution jobExecution = jobLauncherTestUtils.launchJob();

To test a step, you provide the step name to the lanuchStep method.

JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1")

My spring test context defined the JobLauncherTestUtils.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:applicationContext.xml"/>

    <bean id="jobLauncherTestUtils" class="org.springframework.batch.test.JobLauncherTestUtils"/>
</beans>

Job and Step Test

My Spring Junit test class is fairly simple. This is no different than any other Job or Step test class. NOTE: I was not able to get transactions to work for a Job or a Step.

package com.javaninja.batch;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TestJobAndStep {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Test
    public void testJob() throws Exception {
        commonAssertions(jobLauncherTestUtils.launchJob());
    }

    @Test
    public void testStep1() throws Exception {
        commonAssertions(jobLauncherTestUtils.launchStep("step1"));
    }

    private void commonAssertions(JobExecution jobExecution) {
        assertNotNull(jobExecution);

        BatchStatus batchStatus = jobExecution.getStatus();
        assertEquals(BatchStatus.COMPLETED, batchStatus);
        assertFalse(batchStatus.isUnsuccessful());

        ExitStatus exitStatus = jobExecution.getExitStatus();
        assertEquals("COMPLETED", exitStatus.getExitCode());
        assertEquals("", exitStatus.getExitDescription());

        List<Throwable> failureExceptions = jobExecution.getFailureExceptions();
        assertNotNull(failureExceptions);
        assertTrue(failureExceptions.isEmpty());
    }
}

Testing Step-scope components

I was able to have more success with transactions when testing Step-scope components like the JPA-related reader and writer. By using the StepScopeTestExecutionListener in combination with TransactionalTestExecutionListener, I was able to get transactions to work correctly.

The JpaPagingItemReader has the following methods that you need to be concerned with:

  • open – opens the output source.
  • read – reads the data.
  • close – closes the entity manager.

The JpaItemWriter provides the write method that handles all of the writing duties, including flushing the data.

The reader and writer test class is:

package com.javaninja.batch;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.database.JpaPagingItemReader;
import org.springframework.batch.test.MetaDataInstanceFactory;
import org.springframework.batch.test.StepScopeTestExecutionListener;
import org.springframework.batch.test.StepScopeTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
                         StepScopeTestExecutionListener.class,
                         TransactionalTestExecutionListener.class})
@Transactional
@ContextConfiguration
public class TestReaderAndWriter {

    @Autowired
    private JpaPagingItemReader<CamAffiliateEntity> itemReader;

    @Autowired
    private JpaItemWriter<CamAffiliateEntity> itemWriter;

    @Test
    public void testReader() {
        StepExecution execution = MetaDataInstanceFactory.createStepExecution();
        int count = 0;
        try {
            count = StepScopeTestUtils.doInStepScope(execution, () -> {
                int numStates = 0;
                itemReader.open(execution.getExecutionContext());
                CamAffiliateEntity camAffiliateEntity;
                try {
                    while ((camAffiliateEntity = itemReader.read()) != null) {
                        assertNotNull(camAffiliateEntity);
                        assertNotNull(camAffiliateEntity.getAffiliateId());
                        assertNotNull(camAffiliateEntity.getName());
                        assertNotNull(camAffiliateEntity.getChannelId());
                        numStates++;
                    }
                } finally {
                    try { itemReader.close(); } catch (ItemStreamException e) { fail(e.toString());
                    }
                }
                return numStates;
            });
        } catch (Exception e) {
            fail(e.toString());
        }
        assertEquals(12, count);
    }

    @Test
    public void testWriter() throws Exception {
        List<CamAffiliateEntity> usStateEntities = new LinkedList<>();
        CamAffiliateEntity usStateEntity;
        for (int i = 0; i < 100; i++) {
            usStateEntity = new CamAffiliateEntity();
            usStateEntity.setAffiliateId(i);
            usStateEntity.setName("TEST-DELETE-" + i);
            usStateEntity.setChannelId(13);  // test
            usStateEntities.add(usStateEntity);
        }

        StepExecution execution = MetaDataInstanceFactory.createStepExecution();
        StepScopeTestUtils.doInStepScope(execution, () -> {
            itemWriter.write(usStateEntities);
            return null;
        });
    }
}

Summary

This summary provided me with the ability to run by Spring Batch JPA project for the reader and writer repeatedly without having test data-related problems.

The entire project used to write this blog is located on GitHub sheltonn / spring-batch-jpa

February 19th, 2016

Posted In: hibernate, Integration Tests, Java, java ninja, Javaninja, JUnit, Spring, Spring Batch, Test Driven Development, Unit Tests

Leave a Comment

In a previous logback blog entry Hibernate Logging (e.g. JBOSS logging) I showed how to send the JBoss logging to your logback logging configuration.

One thing kept bothering me. If you turned on showSql, these were not captured by your logging. I was fishing through the code and discovered why. If you turn on showSql, it actually sets a variable named logToStdout. Just as the name says, in the code, it logs to STDOUT.

if ( logToStdout ) {
	System.out.println( "Hibernate: " + statement );
}

This results in logging like the following:

Hibernate: insert into cam_affiliate (Channel_ID, Name, Affiliate_ID) values (?, ?, ?)

Logging Sql statements via Logback

A better way is to NOT set showSql to true, but to add the following logger to your Logback configuration.

<!-- Displays the Hibernate SQL statements in your log instead of STDOUT like showSql does-->
<logger name="org.hibernate.SQL" level="DEBUG"/>

This displays logging similar to:

2016-02-19 09:09:30|DEBUG|insert into cam_affiliate (Channel_ID, Name, Affiliate_ID) values (?, ?, ?) ||org.hibernate.engine.jdbc.spi.SqlStatementLogger:92 

February 19th, 2016

Posted In: hibernate, hibernate logging, Java, java ninja, Javaninja, jboss logging, jcl-over-slf4j, log4j-over-slf4j, logback, Logging, Logging configuration, slf4j

Leave a Comment

I was getting the following debug logging, even though my logging config said info and above.

15:14:02.541|DEBUG|RdbmsOperation with SQL [p_select_validate_pin_person_token] compiled||org.springframework.jdbc.object.RdbmsOperation:344
15:14:02.541|DEBUG|Compiled stored procedure. Call string is [{call p_select_validate_sso_person_token(?, ?)}]||org.springframework.jdbc.object.SqlCall:154
15:14:02.541|DEBUG|RdbmsOperation with SQL [p_select_validate_sso_person_token] compiled||org.springframework.jdbc.object.RdbmsOperation:344
15:14:02.542|DEBUG|Compiled stored procedure. Call string is [{call p_delete_truncate(?)}]||org.springframework.jdbc.object.SqlCall:154
15:14:02.542|DEBUG|RdbmsOperation with SQL [p_delete_truncate] compiled||org.springframework.jdbc.object.RdbmsOperation:344
15:14:02.543|DEBUG|Compiled stored procedure. Call string is [{call p_update_setting_inprogress(?)}]||org.springframework.jdbc.object.SqlCall:154

During my research, I learned that Hibernate is logged via JBoss Logging. It used to require a properties file that denoted which logging implementation to use. It now will try to use several logging frameworks, such as commons-logging, log4j and logback. I use Logback.

One common problem is that if you are pulling in lots of dependent libraries, it isn’t uncommon to have multiple logging APIs preset. That was the case that I had.

I checked my dependencies and discovered that I had libraries for:

  • logback-classic – logback is my preferred logging framework.
  • commons-logging – this is the culprit. The JBoss logging API is finding this framework, but isn’t finding a configuration file so everything is being logged.
  • jboss-logging – this is the jboss logging api and is required
  • log4j-over-slf4j – this is the slf4j implementation of the log4j api. In essence, hijacking log4j and funnelling the log4j logging events through slf4j.

To fix this, I had to find every Maven dependency that has a transitive dependency on commons-logging and exclude commons-logging. An example of something that had commons-logging as a transitive dependency was spring-webmvc. I modified the dependency by adding exclusions.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>

Once I removed all commons-logging transitive dependencies, I had to provide a suitable substitute. This is where another SLF4j dependency comes in handy. This is a SLF4J implementation of the commons-logging api which funnels all of the commons-logging events to my slf4J implementation.

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.7</version>
        </dependency>

December 30th, 2014

Posted In: hibernate, hibernate logging, java ninja, Javaninja, jboss, jboss logging, jcl-over-slf4j, log4j-over-slf4j, logback, Logging, slf4j

Tags: , , , , , , , , , ,

2 Comments

LinkedIn Auto Publish Powered By : XYZScripts.com