Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Working with Spring Data JPA repositories is easy if you use them the way they are intended to be used. One way that they don’t like to be used is with two different databases with the objects in the same directories. In a previous blog titled Spring Data JPA with multiple entity managers, I showed how to have multiple EntityManagers work with Spring Data JPA. As part of that, we had to annotate each method that used the repository with @Transactional. I didn’t like this and I was searching for a way to make it better.

I tried to filter the jpa:repositories with a regex, but that wouldn’t work.

I next tried filtering by annotation and it worked like a charm. Here is how I did it.

Create annotations

The annotations are very simple and there isn’t Spring specific about them. I created @ReadOnly and @ReadWrite annotations.

package com.javaninja.adw.spring;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * Annotation used to indicate that this should be picked up as a ReadOnly database operation, specifically for
 * Spring Data JPA repositories.
 * @author norrisshelton
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadOnly {

} 
package com.javaninja.adw.spring;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * Annotation used to indicate that this should be picked up as a ReadWrite database operation, specifically for
 * Spring Data JPA repositories.
 * @author norrisshelton
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadWrite {

} 

Annotate the repositories

I annotated the Read-only repository with @ReadOnly and annotated my Read-Write repository with @ReadWrite.

package com.javaninja.adw.example;


import com.javaninja.adw.spring.ReadOnly;

import org.springframework.data.jpa.repository.JpaRepository;


/**
 * Read-only Spring Data JPA Repository for Example objects.
 * @author norrisshelton
 */
@ReadOnly
public interface RoExampleRepository extends JpaRepository<ExampleEntity, Integer> {

    ExampleEntity findByAffiliateId(int affiliateId);
}
package com.javaninja.adw.example;


import com.javaninja.adw.spring.ReadWrite;

import org.springframework.data.jpa.repository.JpaRepository;


/**
 * Read-write Spring Data JPA Repository for Example objects.
 * @author norrisshelton
 */
@ReadWrite
public interface RwExampleRepository extends JpaRepository<ExampleEntity, Long> {

}

Repository declaration

Once I have that, I can move onto the Spring context configuration. I could then modify my jpa:repositories declaration to look like:

<jpa:repositories base-package="com.javaninja.adw"
                  entity-manager-factory-ref="roEntityManagerFactory"
                  transaction-manager-ref="roTransactionManager">
    <repository:include-filter type="annotation" expression="com.javaninja.adw.spring.ReadOnly"/>
</jpa:repositories>
<jpa:repositories base-package="com.javaninja.adw"
                  entity-manager-factory-ref="rwEntityManagerFactory"
                  transaction-manager-ref="rwTransactionManager">
    <repository:include-filter type="annotation" expression="com.javaninja.adw.spring.ReadWrite"/>
</jpa:repositories>

What does it look like when used

Once those changes are done, using it is as easy as any other usage. No more @Transactional annotations.

package com.javaninja.adw.example;


import com.javaninja.adw.ExampleModel;

import org.springframework.stereotype.Service;


/**
 * @author norris.shelton
 */
@Service
public class ExampleService {

    private final RoExampleRepository roExampleRepository;

    public ExampleService(RoExampleRepository roExampleRepository) {
        this.roExampleRepository = roExampleRepository;
    }

    /**
     * Gets an example model object.
     * @return populated example model
     */
    public ExampleModel getExampleModel(int affiliateId) {
        ExampleEntity exampleEntity = roExampleRepository.findByAffiliateId(affiliateId);
        ExampleModel exampleModel = new ExampleModel();
        exampleModel.setExampleProperty(exampleEntity.getName());
        return exampleModel;
    }
}

The rest of the Spring Context

The rest of the Spring Context configuration looks the same. There is two of anything. To prevent confusion, I pre-pended ro or rw to all of my objects.

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<util:properties id="jpaProperties">
    <!--<prop key="hibernate.show_sql">false</prop>-->
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</util:properties>
<bean id="rwEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="rwAdwDataSource"
      p:packagesToScan="com.javaninja.adw"
      p:persistenceUnitName="rwPersistenceUnit"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:jpaProperties-ref="jpaProperties"/>
<bean id="roEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="roAdwDataSource"
      p:packagesToScan="com.javaninja.adw"
      p:persistenceUnitName="roPersistenceUnit"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:jpaProperties-ref="jpaProperties"/>
<!--
    Transaction-related configuration
-->
<tx:annotation-driven/>
<bean id="rwTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="rwEntityManagerFactory"/>
    <qualifier value="rw"/>
</bean>
<bean id="roTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="roEntityManagerFactory"/>
    <qualifier value="ro"/>
</bean>

May 3rd, 2017

Posted In: Java, java ninja, Javaninja, Spring, Spring Data, Spring Data JPA

Leave a Comment

We are using -D system parameters to define our connection pool values. They were defined in a Tomcat setenv file in the bin directory.

export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-JDBC=jdbc:mysql://192.168.0.1/javaninja?zeroDateTimeBehavior=convertToNull"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO--- USER=javaninja"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-PASS=javaninja"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-INITIAL-SIZE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MIN-IDLE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MAX-IDLE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MAX-TOTAL=15"

The parameters appeared to be read correctly, as evidenced by the Tomcat log.

14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-JDBC=jdbc:mysql://192.168.0.1/javaninja?zeroDateTimeBehavior=convertToNull
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO--- USER=javaninja
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-PASS=javaninja
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-INITIAL-SIZE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MIN-IDLE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MAX-IDLE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MAX-TOTAL=15

This did not work. We would get weird messages about the value not being in range. This was due to one of the values having noAccessToProcedureBodies=true. The JDBC driver expected yes, no, true or false Unfortunately, what it was receiving was true\n. I have no idea where the newline was coming from. I deleted the end of the line and typed the characters myself, but they were still there.

The solution was to trim all of the values of control characters. Apache StringUtils is my preferred tool for that; however, it is a static class and Spring doesn’t like that. To get over that, I instantiated a copy of it.

<bean id="stringUtils" class="org.apache.commons.lang3.StringUtils"/>

Once I had a StringUtils bean, I used it to trim the values by

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
      p:driverClassName="com.mysql.jdbc.Driver"
      p:url="#{stringUtils.trim(systemProperties['PROXY-RO-JDBC'])}"
      p:username="#{stringUtils.trim(systemProperties['PROXY-RO--- USER'])}"
      p:password="#{stringUtils.trim(systemProperties['PROXY-RO-PASS'])}"
      p:initialSize="#{stringUtils.trim(systemProperties['PROXY-RO-INITIAL-SIZE'])}"
      p:maxTotal="#{stringUtils.trim(systemProperties['PROXY-RO-MAX-TOTAL'])}"
      p:maxIdle="#{stringUtils.trim(systemProperties['PROXY-RO-MAX-IDLE'])}"
      p:minIdle="#{stringUtils.trim(systemProperties['PROXY-RO-MIN-IDLE'])}"
      p:testOnBorrow="false"
      p:timeBetweenEvictionRunsMillis="60000"
      p:testWhileIdle="true"/>

December 14th, 2016

Posted In: Java, java ninja, Javaninja, Spring

Leave a Comment

In the previous blog entry titled Turning Spring MVC exceptions into status codes with messages, I mapped exceptions into HTTP status codes.

Test Controller

In this blog we will test those and verify that everything is working correctly. I started with a test controller that I would use to generate the exceptions and the message. I created controller methods that would generate consistent results:

  • ResourceException with an HTTP 400 and a message
  • ResourceException with an HTTP 404 and a message
  • RuntimeException without any developer customization
  • Exception with a message

I wanted to ensure that I had consistent behavior and I was able to pull information from the exception that would be relevant to the client/consumer, but I also wanted to ensure that I never returned a stacktrace to the outside world.

package com.javaninja.cam.spring;


import com.javaninja.cam.dto.Prospect;
import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

    @RequestMapping(value = "/test/resourceException400")
    public Prospect getResourceException400() {
        throw new ResourceException(HttpStatus.BAD_REQUEST, "Test Bad Request Exception message");
    }

    @RequestMapping(value = "/test/resourceException404")
    public Prospect getResourceException404() {
        throw new ResourceException(HttpStatus.NOT_FOUND, "Test Not Found Exception message");
    }

    @RequestMapping(value = "/test/runtimeException")
    public int getRuntimeException() {
        return Integer.parseInt("x");
    }

    @RequestMapping(value = "/test/exception")
    public int getException() throws Exception {
        throw new Exception("Test Exception message");
    }
}

Junit Test Class

Once that was written, it was fairly easy to test the results. I used MockMVC with Spring Test to implement my test class. As part of this test, I wanted to ensure that the custom ResourceException that I created was handled correctly. I also wanted to ensure that I could handle RuntimeExceptions that happened during regular program execution could be handled. The last thing I wanted to verify was that developer created and thrown exceptions could be handled and that the message that they were created with was outputted correctly. I checked the HTTP status and the content for each type of exception.

package com.javaninja.cam.spring;


import com.javaninja.cam.JunitTestUtility;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@WebAppConfiguration
public class TestCamControllerAdvice {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    /**
     * Needed because we have some legacy code that intereactes directly with the context.  This is NOT normal and 
     * will be removed as the project is modernized. 
     * @throws Exception
     */
    @BeforeClass
    public static void createMockContext() throws Exception {
        JunitTestUtility.setup();
    }

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 400 with the expected message.
     */
    @Test
    public void testResourceException400() {
        try {
            mockMvc.perform(get("/test/resourceException400"))
                   .andExpect(status().isBadRequest())
                   .andExpect(content().string("Test Bad Request Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 404 with the expected message.
     */
    @Test
    public void testResourceException404() {
        try {
            mockMvc.perform(get("/test/resourceException404"))
                   .andExpect(status().isNotFound())
                   .andExpect(content().string("Test Not Found Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that a RuntimeException is received and that it returns the expected message.
     */
    @Test
    public void testRuntimeException() {
        try {
            mockMvc.perform(get("/test/runtimeException"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("java.lang.NumberFormatException: For input string: \"x\""))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that an Exception is received and that it returns the expected message.
     */
    @Test
    public void testException() {
        try {
            mockMvc.perform(get("/test/exception"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("Test Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

MockMVC Print Output

For readability, I also displayed the full MockMVC print output. The output makes it very clear that I received the anticipated information and nothing else. The example output is below:

com.javaninja.cam.spring.TestCamControllerAdvice

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/exception
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.twinspires.cam.spring.TestController.getException() throws java.lang.Exception

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.Exception

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[22]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException400
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException400()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = {Content-Type=, Content-Length=[34]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Bad Request Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException404
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException404()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {Content-Type=, Content-Length=[32]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Not Found Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/runtimeException
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.javaninja.cam.spring.TestController.getRuntimeException()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.NumberFormatException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[54]}
     Content type = text/plain;charset=ISO-8859-1
             Body = java.lang.NumberFormatException: For input string: "x"
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Process finished with exit code 0

There you have it. A full Junit/MockMVC test harness that can be used to determine if a SpringMVC controller is returning the correct information when you are trying to map Exceptions into HTTP status codes, along with messages that can be returned with the client consumer.

November 16th, 2016

Posted In: Java, java ninja, Javaninja, JUnit, MockMVC, Spring, Spring MVC, Test Driven Development

Leave a Comment

In the original blog entry, Throwing exceptions with messages from a SpringMVC controller I set up a system to allow exceptions that would be thrown to cause an HTTP status code to be sent to the consumer with a message.

I needed to expand upon that to handle all of the exceptions that my Spring MVC controllers could encounter. To accomplish that, I created a class and annotated it with @ControllerAdvice. This allowed me to create a ExceptionHandlers for all of my controllers in one place.

I created three mappings because I wanted to handle the three types of exceptions a little differently than the others.

  • ResourceException – allows me to set a HTTP status and a message
  • RuntimeException – these are not typically created by developers I need to grab all of the information that I can. That is why I used the toString. That contains the name of the exception and the system specified message.
  • Exception – these are checked exceptions and are created by developers within their code. The expectation is that they put a meaningful message in the message property.

This was fairly easy to accomplish by having three different exception mappings. Within each exception mapping, I set the values in the ResponseEntity to display the appropriate HTTP status with a message in the content.

package com.javaninja.cam.spring;


import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;


/**
 * Exception handler advice class for all SpringMVC controllers.
 * @author norrisshelton
 * @see ControllerAdvice
 */
@ControllerAdvice
public class CamControllerAdvice {

    /**
     * Returns whatever HTTP status was set within the ResourceException.  Uses the message that was set when
     * the ResourceException was created.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(ResourceException.class)
    public ResponseEntity handleResourceException(ResourceException e) {
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }

    /**
     * Sets the HTTP status as INTERNAL_SERVER_ERROR (500).  Uses the toString of the exception because
     * RuntimeExceptions don't always have enough usable information in the message property.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity handleRuntimeException(RuntimeException e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.toString());
    }

    /**
     * Sets the HTTP status as INTERNAL_SERVER_ERROR (500).  Uses the message property under the assumption that the
     * developer that created the exception set a meaningful explanation in the message property.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleException(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
    }
}

November 16th, 2016

Posted In: Java, java ninja, Javaninja, Spring, Spring MVC

One Comment

The Maven Checkstyle Plugin is very useful to identity source files that do not follow your source coding standards. We chose to follow what Google used for their Checkstyle as the basis for ours. We made small tweaks to their standard, but those are contained within the declared file. Please note that Google used a new rule that wasn’t contained within the libraries that were included by the version of the maven-checkstyle-plugin that was available. To enable this additional functionality, we explicitly declared the version of the puppycrawl checkstyle dependency to use.

I configured the plugin to generate reports and to not fail on error, but to give warnings instead.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.17</version>
    <dependencies>
        <!--
        http://mvnrepository.com/artifact/com.puppycrawl.tools/checkstyle
        Needed because Google uses a new checkstyle that isn't included by the regular plugin.
        https://groups.google.com/forum/#!topic/checkstyle/OXux8RqJuXg
        -->
        <dependency>
            <groupId>com.puppycrawl.tools</groupId>
            <artifactId>checkstyle</artifactId>
            <version>6.19</version>
        </dependency>
    </dependencies>
    <executions>
        <execution>
            <goals>
                <goal>checkstyle</goal>
            </goals>
            <phase>verify</phase>
        </execution>
    </executions>
    <configuration>
        <configLocation>twinspires_checkstyle.xml</configLocation>
        <encoding>UTF-8</encoding>
        <consoleOutput>true</consoleOutput>
        <failOnViolation>false</failOnViolation>
        <linkXRef>false</linkXRef>
        <enableRulesSummary>true</enableRulesSummary>
        <enableSeveritySummary>true</enableSeveritySummary>
        <enableFilesSummary>true</enableFilesSummary>
        <includeTestSourceDirectory>true</includeTestSourceDirectory>
    </configuration>
</plugin>
<plugin>

The output of the plugin will contain the name of the Java class, the line number and a brief description of what the warning is, along with the checkstyle caregory. Example output is below:

[INFO] --- maven-checkstyle-plugin:2.17:checkstyle (default) @ newcam-server ---
[INFO] Starting audit...
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:10: Using the '.*' form of import should be avoided - com.twinspires.cam.entity.*. [AvoidStarImport]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:58: Using the '.*' form of import should be avoided - com.twinspires.cam.response.*. [AvoidStarImport]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:82: First sentence of Javadoc is incomplete (period is missing) or not present. [SummaryJavadoc]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:98: Abbreviation in name 'registerWageringCustomerInRAFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:125: Abbreviation in name 'updateCustomerSSNFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:177: First sentence of Javadoc is incomplete (period is missing) or not present. [SummaryJavadoc]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:194: First sentence of Javadoc is incomplete (period is missing) or not present. [SummaryJavadoc]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:350:5: Missing a Javadoc comment. [JavadocMethod]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:363:5: Missing a Javadoc comment. [JavadocMethod]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:517:9: '}' at column 9 should be on the same line as the next part of a multi-block statement (one that directly contains multiple blocks: if/else-if/else or try/catch/finally). [RightCurly]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:533:20: Method name 'eCommerceCustomerPreUpdateCheck' must match pattern '^[a-z][a-z0-9][a-zA-Z0-9_]*$'. [MethodName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:538: Abbreviation in name 'emailDTO' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:554: Abbreviation in name 'dtoCountryByISOCode' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:755:5: Missing a Javadoc comment. [JavadocMethod]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:801: Distance between variable 'failReason' declaration and its first usage is 7, but allowed 3.  Consider to make that variable as final if you still need to store its value in advance (before method calls that might do side effect on original value). [VariableDeclarationUsageDistance]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:940: Abbreviation in name 'setRegisterWageringCustomerInRAFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:941: Abbreviation in name 'registerWageringCustomerInRAFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:1155: Abbreviation in name 'setUpdateCustomerSSNFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:1155: Abbreviation in name 'updateCustomerSSNFacade' must contain no more than '1' capital letters. [AbbreviationAsWordInName]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/CustomerServicesManagerImpl.java:1257: Line is longer than 120 characters (found 129). [LineLength]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/ICustomerServicesManager.java:47: Using the '.*' form of import should be avoided - com.twinspires.cam.response.*. [AvoidStarImport]
[WARN] /Users/norrisshelton/IdeaProjects/newcam/newcam-server/src/main/java/com/twinspires/cam/biz/ICustomerServicesManager.java:52: Abbreviation in name 'verifySSN' must contain no more than '1' capital letters. [AbbreviationAsWordInName]

October 19th, 2016

Posted In: java ninja, Javaninja, Maven

Leave a Comment

The Maven Dependency Plugin can give you dependency related information for your Maven projects. I use it for two main purposes

  • Dependencies that I declare, but do NOT use
  • Dependencies that I do NOT care, but do use

The minimal configuration is as follows:

            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>analyze</id>
                        <goals>
                            <goal>analyze-only</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

The normal behavior is to break the build when there is a problem. I was working on a pre-existing project and we were going to have to work through the problems over time, so this was counter-productive. To disable this behavior, I set the plugin to to fail on warnings. Another thing that I do is enable the output of XML for any used, but undeclared dependencies. This makes it very easy to copy/paste the missing dependencies.

            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>analyze</id>
                        <goals>
                            <goal>analyze-only</goal>
                        </goals>
                        <configuration>
                            <failOnWarning>false</failOnWarning>
                            <outputXML>true</outputXML>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

This is what sample output will look like. There are three different sections.

  • Used, but undeclared dependencies. These should be added to your POM file. You can copy the XML elements in the last section to easily add these.
  • Unused, but declared dependencies. These can usually be removed from your POM files. Please be aware that some dependencies are not explicitly declared and are determined at run-time (e.g Spring has multiple implementations for various functions).
  • The XML for the used, but undeclared dependencies. These XML snippets should be added to your POM files. This prevents your project from breaking when a dependency library changes its dependencies and inadvertantly breaks your build.
[INFO] --- maven-dependency-plugin:2.10:analyze-only (analyze) @ newcam-server ---
[WARNING] Used undeclared dependencies found:
[WARNING]    com.google.code.gson:gson:jar:2.5:compile
[WARNING] Unused declared dependencies found:
[WARNING]    com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.7.0:compile
[WARNING]    org.hibernate:hibernate-validator:jar:4.1.0.Final:compile
[WARNING]    mysql:mysql-connector-java:jar:5.1.34:provided
[WARNING]    org.hibernate:hibernate-entitymanager:jar:4.3.11.Final:compile
[WARNING]    org.slf4j:jcl-over-slf4j:jar:1.7.13:compile
[WARNING]    org.springframework:spring-orm:jar:4.2.4.RELEASE:compile
[WARNING]    org.slf4j:log4j-over-slf4j:jar:1.7.13:compile
[WARNING]    org.apache.commons:commons-dbcp2:jar:2.1:test
[WARNING]    org.apache.cxf:cxf-rt-frontend-jaxrs:jar:3.1.4:compile
[WARNING]    ch.qos.logback:logback-classic:jar:1.1.3:compile
[WARNING]    org.codehaus.jackson:jackson-xc:jar:1.9.13:compile
[INFO] Add the following to your pom to correct the missing dependencies: 
[INFO] 
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.5</version>
</dependency>
[INFO] 

October 19th, 2016

Posted In: java ninja, Javaninja, Maven

Leave a Comment

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

The Problem

We had a service written in Java that retrieved a number from the database and returned it through a RESTful service to a Javascript client. The number was a long because of it’s large size. This had worked for a very long time. However, we noticed that when we had some very large numbers, the number started to be off by one. Specifically,

9164083756384584
9597642508289680

Those values were displayed as

9164083756384585
9597642508289681

In Java, we are used to overflow behavior being represented by a number turning negative because the signed bit is being used to represent data.

The Findings

We were able to verify that when we called the service with Postman, that we did see the correct value. The problem occurred when the Javascript client tried to parse the data. There was a specific line where the value was taken from the json to string marshalled object and it was converted to a string. This is where the problem was. After much searching and consulting with our Javascript experts, we ended up with ECMA 8.5 The Number Type. What an eye opener. This confirmed to us that the largest number that we could expect to be retrieved from our Java RESTful services was 2^53-1, not 2^63-1.

We had no idea that 9007199254740991 was the largest value that we could expect to be represented accurately in Javascript.

The Solution

Our solution was to add a property to the object that we were returning for marshalling by our Java RESTful services. We updated the service to have an additional property that was a String. Meaning that we would transition to return a String as our record IDs, instead of a long. This was fine, since arithmetic operations shouldn’t be performed on our object IDs anyway.

More Findings

We also found supporting information at

  • http://stackoverflow.com/questions/307179/what-is-javascripts-highest-integer-value-that-a-number-can-go-to-without-losin
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_VALUE

October 4th, 2016

Posted In: ECMA, ECMAscript, Java, java ninja, Javaninja, javascript

Leave a Comment

The SpringFramework has a RestTemplate object that can be used to HTTP-based network calls. It doesn’t timeout by default, but there is functionality that can be configured. A RequestFactory must be created, then it needs to be wired into the RestTemplate.

The readTimeout and the connectionTimeout are both expressed in milliseconds.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd>
 
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"
          p:readTimeout="250"
          p:connectTimeout="250"/>
 
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"
          c:requestFactory-ref="requestFactory"/>
</beans>

Once you have the RequestFactory configured, then the RestTemplate will begin to throw SocketTimeoutException and ConnectTimeoutException, depending on the problem. This is normally handled by catching RestClientException. This RuntimeException wraps all exceptions that are throws by the RestTemplate.

String response = null;
try {
    response = restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
    createOrderResponse.setStatus("failure");
    logger.error("Unable to get the PayNearMe barcode URL", e);
    //FIXME do something with the exception
    //throw e;
}

Catching the RestClientException is usually enough, because you only want to know that there is a problem. However, if you need to know the specific problem, you can test the RootCause for the specific type of exception.

String response = null;
try {
    response = restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
    createOrderResponse.setStatus("failure");
    if (e.getRootCause() instanceof SocketTimeoutException) {
        logger.error("SocketTimeoutException", e);
    } else if (e.getRootCause() instanceof ConnectTimeoutException) {
        logger.error("ConnectTimeoutException", e);
    } else {
        logger.error("Some other exception", e);
    }
    //FIXME do something with the exception
    //throw e;
}

September 13th, 2016

Posted In: Java, java ninja, Javaninja, Spring

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

Next Page »
LinkedIn Auto Publish Powered By : XYZScripts.com